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

Revision 2171, 23.9 kB (checked in by jwoithe, 12 years ago)

A second pass at addressing ticket #242. Define a global clock source within the SystemTimeSource? object and use this whenever clock_gettime() is called. On systems which support the new raw1394_read_cycle_timer_and_clock() libraw1394 call and CLOCK_MONOTONIC_RAW, these changes should ensure that all timing-sensitive parts of FFADO are using the same clock source. System tests under tests/systemtests/ have not been converted to use this new framework because they exist for different purposes and are not using the FFADO streaming infrastructure.

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