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

Revision 2802, 24.9 kB (checked in by jwoithe, 3 years ago)

Cosmetic: "Firewire" becomes "FireWire?".

Officially both the "F" and "W" were capitalised in the FireWire? name, so
reflect this throughout FFADO's source tree. This mostly affects comments.

This patch originated from pander on the ffado-devel mailing list. To
maintain consistency, the committed version has been expanded to include
files not originally included in the original patch.

  • 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 #include "libutil/Time.h"
30
31 #include <iostream>
32
33 #include <time.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #if DEBUG_BACKTRACE_SUPPORT
38     #include <execinfo.h>
39     #include <cxxabi.h>
40     #define GNU_SOURCE
41     #include <dlfcn.h>
42 #endif
43
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
52
53 using namespace std;
54
55 struct ColorEntry  {
56     const char* preSequence;
57     const char* postSequence;
58 };
59
60 ColorEntry colorTable[] = {
61     { "",           ""        },
62     { "\033[31mFatal",   "\033[0m" },
63     { "\033[31mError",   "\033[0m" },
64     { "\033[31mWarning", "\033[0m" },
65     { "Debug",           ""        },
66 };
67
68
69 DebugModule::DebugModule( std::string name,  debug_level_t level )
70     : m_name( name )
71     , m_level( level )
72 {
73     if ( !DebugModuleManager::instance()->registerModule( *this ) ) {
74         cerr << "Could not register DebugModule (" << name
75              << ") at DebugModuleManager"
76              << endl;
77     }
78 }
79
80 DebugModule::~DebugModule()
81 {
82 //     if ( m_level >= eDL_VeryVerbose ) {
83 //         cout << "Unregistering "
84 //              << this->getName()
85 //              << " at DebugModuleManager"
86 //              << endl;
87 //     }
88
89     if (m_manager && !m_manager->unregisterModule( *this ) ) {
90         cerr << "Could not unregister DebugModule at DebugModuleManager"
91              << endl;
92     }
93
94 }
95
96 void
97 DebugModule::printShort( debug_level_t level,
98                          const char* format,
99                          ... ) const
100 {
101
102     // bypass for performance
103 #if DEBUG_BACKLOG_SUPPORT
104     if (level > BACKLOG_MIN_LEVEL
105         && level > m_level) {
106         return;
107     }
108 #else
109     if ( level >m_level ) {
110         return;
111     }
112 #endif
113
114     const char *warning = "WARNING: message truncated!\n";
115     const int warning_size = 32;
116     va_list arg;
117     char msg[MB_BUFFERSIZE];
118
119     // format the message such that it remains together
120     int chars_written=0;
121     int retval=0;
122
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;
128     }
129
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);
133     }
134
135 #if DEBUG_BACKLOG_SUPPORT
136     // print to backlog if necessary
137     if (level <= BACKLOG_MIN_LEVEL) {
138         DebugModuleManager::instance()->backlog_print( msg );
139     }
140 #endif
141
142     // print to stderr if necessary
143     if ( level <= m_level ) {
144         DebugModuleManager::instance()->print( msg );
145     }
146 }
147
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
155 {
156     // bypass for performance
157 #if DEBUG_BACKLOG_SUPPORT
158     if (level > BACKLOG_MIN_LEVEL
159         && level > m_level) {
160         return;
161     }
162 #else
163     if ( level >m_level ) {
164         return;
165     }
166 #endif
167
168     const char *warning = "WARNING: message truncated!\n";
169     const int warning_size = 32;
170
171     va_list arg;
172     char msg[MB_BUFFERSIZE];
173
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;
180     }
181
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);
186
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
194
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
201
202     retval = snprintf( msg + chars_written,
203                        MB_BUFFERSIZE - chars_written,
204                        "%s", getPostSequence( level ) );
205     if (retval >= 0) chars_written += retval; // ignore errors
206
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);
212     }
213
214 #if DEBUG_BACKLOG_SUPPORT
215     // print to backlog if necessary
216     if (level <= BACKLOG_MIN_LEVEL) {
217         DebugModuleManager::instance()->backlog_print( msg );
218     }
219 #endif
220
221     // print to stderr if necessary
222     if ( level <= m_level ) {
223         DebugModuleManager::instance()->print( msg );
224     }
225 }
226
227 const char*
228 DebugModule::getPreSequence( debug_level_t level ) const
229 {
230     if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
231         return colorTable[level].preSequence;
232     }
233     return colorTable[eDL_Normal].preSequence;
234 }
235
236 const char*
237 DebugModule::getPostSequence( debug_level_t level ) const
238 {
239     if ( ( level <= eDL_Normal ) && ( level >= eDL_Message ) ) {
240         return colorTable[level].postSequence;
241     }
242     return colorTable[eDL_Normal].postSequence;
243 }
244
245 //--------------------------------------
246
247 DebugModuleManager* DebugModuleManager::m_instance = 0;
248
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
262 {
263
264 }
265
266 DebugModuleManager::~DebugModuleManager()
267 {
268     // cleaning up leftover modules
269     while (!m_debugModules.empty())
270     {
271         DebugModule *mod = m_debugModules.back();
272         unregisterModule(*mod);
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 messagebuffer thread: %s (%d)\n", strerror(res), res);
377         return -1;
378     }
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;
382     }
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;
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 messagebuffer thread: %s (%d)\n", strerror(res), 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 messagebuffer thread: %s (%d)\n", strerror(res), 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 RT messagebuffer thread: %s (%d)\n", strerror(res), res);
406         mb_initialized = 0;
407     }
408
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");
422         }
423     }
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;
429     }
430     #endif
431 #endif
432
433     return true;
434 }
435
436 DebugModuleManager*
437 DebugModuleManager::instance()
438 {
439     if ( !m_instance ) {
440         m_instance = new DebugModuleManager;
441         if ( !m_instance ) {
442             cerr << "DebugModuleManager::instance Failed to create "
443                  << "DebugModuleManager" << endl;
444         }
445         if ( !m_instance->init() ) {
446             cerr << "DebugModuleManager::instance Failed to init "
447                  << "DebugModuleManager" << endl;
448         }
449     }
450     return m_instance;
451 }
452
453 bool
454 DebugModuleManager::registerModule( DebugModule& debugModule )
455 {
456     bool already_present=false;
457
458     for ( DebugModuleVectorIterator it = m_debugModules.begin();
459           it != m_debugModules.end();
460           ++it )
461     {
462         if ( *it == &debugModule ) {
463             already_present=true;
464             return true;
465         }
466     }
467
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;
475     }
476     return true;
477 }
478
479 bool
480 DebugModuleManager::unregisterModule( DebugModule& debugModule )
481 {
482
483     for ( DebugModuleVectorIterator it = m_debugModules.begin();
484           it != m_debugModules.end();
485           ++it )
486     {
487         if ( *it == &debugModule ) {
488             m_debugModules.erase( it );
489             if (debugModule.m_manager == this)
490                 debugModule.m_manager = NULL;
491             return true;
492         }
493     }
494
495     cerr << "DebugModuleManager::unregisterModule: Could not unregister "
496          << "DebugModule (" << debugModule.getName() << ")" << endl;
497     return false;
498 }
499
500 bool
501 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
502 {
503     for ( DebugModuleVectorIterator it = m_debugModules.begin();
504           it != m_debugModules.end();
505           ++it )
506     {
507         if ( (*it)->getName() == name ) {
508             return (*it)->setLevel( level );
509         }
510     }
511
512     cerr << "setDebugLevel: Did not find DebugModule ("
513          << name << ")" << endl;
514     return false;
515 }
516
517 void
518 DebugModuleManager::flush()
519 {
520 #if DEBUG_USE_MESSAGE_BUFFER
521     mb_flush();
522 #else
523     fflush(stderr);
524 #endif
525 }
526
527 #if DEBUG_USE_MESSAGE_BUFFER
528 void
529 DebugModuleManager::mb_flush()
530 {
531     /* called WITHOUT the mb_write_lock */
532    
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.
537      */
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);
543     }
544     fflush(stderr);
545     pthread_mutex_unlock(&m->mb_flush_lock);
546 }
547
548 void *
549 DebugModuleManager::mb_thread_func(void *arg)
550 {
551
552     DebugModuleManager *m=static_cast<DebugModuleManager *>(arg);
553
554     while (m->mb_initialized) {
555         sem_wait(&m->mb_writes);
556         m->mb_flush();
557     }
558
559     return NULL;
560 }
561 #endif
562
563 #if DEBUG_BACKLOG_SUPPORT
564 void
565 DebugModuleManager::showBackLog()
566 {
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");
574
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);
579     }
580     fprintf(stderr, "BL: \n");
581
582     fprintf(stderr, "=====================================================\n");
583     fprintf(stderr, "* END OF BACKLOG PRINT\n");
584     fprintf(stderr, "=====================================================\n");
585     pthread_mutex_unlock(&m->mb_flush_lock);
586 }
587
588 void
589 DebugModuleManager::showBackLog(int nblines)
590 {
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");
598
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);
606         }
607     }
608     fprintf(stderr, "BL: \n");
609
610     fprintf(stderr, "=====================================================\n");
611     fprintf(stderr, "* END OF BACKLOG PRINT\n");
612     fprintf(stderr, "=====================================================\n");
613     pthread_mutex_unlock(&m->mb_flush_lock);
614 }
615
616 void
617 DebugModuleManager::backlog_print(const char *msg)
618 {
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--;
632         }
633     }
634     // just bail out should it have failed
635 }
636 #endif
637
638 void
639 DebugModuleManager::print(const char *msg)
640 {
641 #if DEBUG_USE_MESSAGE_BUFFER
642     unsigned int ntries;
643     struct timespec wait = {0,50000};
644
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;
651     }
652
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--;
664         }
665     }
666     if (ntries==0) {  /* lock collision */
667         //         atomic_add(&mb_overruns, 1);
668         // FIXME: atomicity
669         mb_overruns++; // skip the atomicness for now
670     }
671 #else
672     fprintf(stderr,msg);
673 #endif
674 }
675
676 #if DEBUG_BACKTRACE_SUPPORT
677 void
678 DebugModuleManager::printBacktrace(int len)
679 {
680     int nptrs;
681     int chars_written=0;
682
683     if(len > DEBUG_MAX_BACKTRACE_LENGTH) {
684         len = DEBUG_MAX_BACKTRACE_LENGTH;
685     }
686
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);
690
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);
696     }
697     chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "\n");
698
699     // make sure the string is terminated properly
700     m_backtrace_strbuffer[MB_BUFFERSIZE-2] = '\n';
701     m_backtrace_strbuffer[MB_BUFFERSIZE-1] = 0;
702    
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;
713             }
714         }
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++;
719         }
720     }
721
722     print(m_backtrace_strbuffer);
723
724     pthread_mutex_unlock(&m_backtrace_lock);
725 }
726
727 void *
728 DebugModuleManager::getBacktracePtr(int id)
729 {
730     int nptrs;
731     void *retval = NULL;
732
733     if(id >= DEBUG_MAX_BACKTRACE_LENGTH) {
734         return NULL;
735     }
736
737     pthread_mutex_lock(&m_backtrace_lock);
738     nptrs = backtrace(m_backtrace_buffer, id+1);
739     if(id >= nptrs) {
740         id = nptrs-1;
741     }
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;
751         }
752     }
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++;
757     }
758     pthread_mutex_unlock(&m_backtrace_lock);
759
760     return retval;
761 }
762
763 void
764 DebugModuleManager::getFunctionName(void *ptr, char *buff, int len)
765 {
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);
777             }
778         } else {
779             snprintf(buff, len, "%p (%s)", ptr, info.dli_sname);
780         }
781     } else {
782         snprintf(buff, len, "%p (I-ERR)", ptr);
783     }
784     if (outbuf) free(outbuf);
785 }
786
787 #endif
788
789 //----------------------------------------
790
791 unsigned char
792 toAscii( unsigned char c )
793 {
794     if ( ( c > 31 ) && ( c < 126) ) {
795         return c;
796     } else {
797         return '.';
798     }
799 }
800
801 /* converts a quadlet to a uchar * buffer
802  * not implemented optimally, but clear
803  */
804 void
805 quadlet2char( quadlet_t quadlet, unsigned char* buff )
806 {
807     *(buff)   = (quadlet>>24)&0xFF;
808     *(buff+1) = (quadlet>>16)&0xFF;
809     *(buff+2) = (quadlet>> 8)&0xFF;
810     *(buff+3) = (quadlet)    &0xFF;
811 }
812
813 void
814 hexDump( unsigned char *data_start, unsigned int length )
815 {
816     unsigned int i=0;
817     unsigned int byte_pos;
818     unsigned int bytes_left;
819
820     if ( length <= 0 ) {
821         return;
822     }
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",
827
828                     i,
829
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),
838
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) )
847                 );
848         }
849     }
850     byte_pos = i;
851     bytes_left = length - byte_pos;
852
853     printf( "%04X:" ,i );
854     for ( i = byte_pos; i < length; i += 1 ) {
855         printf( " %02X", *(data_start+i) );
856     }
857     for ( i=0; i < 8-bytes_left; i+=1 ) {
858         printf( "   " );
859     }
860
861     printf( " - [" );
862     for ( i = byte_pos; i < length; i += 1) {
863         printf( "%c", toAscii(*(data_start+i)));
864     }
865     for ( i = 0; i < 8-bytes_left; i += 1) {
866         printf( " " );
867     }
868
869     printf( "]" );
870     printf( "\n" );
871 }
872
873 void
874 hexDumpQuadlets( quadlet_t *data, unsigned int length )
875 {
876     unsigned int i=0;
877
878     if ( length <= 0 ) {
879         return;
880     }
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]));
884     }
885 }
886
887
Note: See TracBrowser for help on using the browser.