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

Revision 1134, 22.0 kB (checked in by ppalmers, 16 years ago)

revert r1131 since it's does unconditional byteswapping

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