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

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

implement endian fixes (thx Heikki Lindholm)
switch from network host order byteswap routines to size based swap routines to remove ambiguity in definition of "long"

  • 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 <byteswap.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],bswap_32(data[i]));
805     }
806 }
807
808
Note: See TracBrowser for help on using the browser.