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

Revision 1157, 21.7 kB (checked in by ppalmers, 15 years ago)

fix race condition in debug module

  • 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 "libutil/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     sem_post(&mb_writes);
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     sem_destroy(&mb_writes);
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_BACKTRACE_SUPPORT
329     pthread_mutex_init(&m_backtrace_lock, NULL);
330 #endif
331
332 #if DEBUG_BACKLOG_SUPPORT
333     pthread_mutex_init(&bl_mb_write_lock, NULL);
334 #endif
335
336 #if DEBUG_USE_MESSAGE_BUFFER
337     pthread_mutex_init(&mb_flush_lock, NULL);
338     pthread_mutex_init(&mb_write_lock, NULL);
339     sem_init(&mb_writes, 0, 0);
340
341     mb_overruns = 0;
342
343     int res;
344     #if DEBUG_MESSAGE_BUFFER_REALTIME
345     /* Get the client thread to run as an RT-FIFO
346         scheduled thread of appropriate priority.
347     */
348     pthread_attr_t attributes;
349     struct sched_param rt_param;
350     pthread_attr_init(&attributes);
351     if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
352         fprintf(stderr, "Cannot request explicit scheduling for RT thread  %d %s\n", res, strerror(res));
353         return -1;
354     }
355     if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
356         fprintf(stderr, "Cannot request joinable thread creation for RT thread  %d %s\n", res, strerror(res));
357         return -1;
358     }
359     if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
360         fprintf(stderr, "Cannot set scheduling scope for RT thread %d %s\n", res, strerror(res));
361         return -1;
362     }
363
364     if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO))) {
365
366     //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
367         fprintf(stderr, "Cannot set FIFO scheduling class for RT thread  %d %s\n", res, strerror(res));
368         return -1;
369     }
370
371     memset(&rt_param, 0, sizeof(rt_param));
372     rt_param.sched_priority = DEBUG_MESSAGE_BUFFER_REALTIME_PRIO;
373
374     if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
375         fprintf(stderr, "Cannot set scheduling priority for RT thread %d %s\n", res, strerror(res));
376         return -1;
377     }
378
379     mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
380     if ((res = pthread_create(&mb_writer_thread, &attributes, mb_thread_func, (void *)this))) {
381         fprintf(stderr, "Cannot create thread %d %s\n", res, strerror(res));
382         mb_initialized = 0;
383     }
384     #else
385     mb_initialized = 1; // set to 1 otherwise the thread might exit (race condition)
386     if ((res = pthread_create(&mb_writer_thread, NULL, &mb_thread_func, (void *)this))) {
387         fprintf(stderr, "Cannot create thread %d %s\n", res, strerror(res));
388         mb_initialized = 0;
389     }
390     #endif
391 #endif
392
393     return true;
394 }
395
396 DebugModuleManager*
397 DebugModuleManager::instance()
398 {
399     if ( !m_instance ) {
400         m_instance = new DebugModuleManager;
401         if ( !m_instance ) {
402             cerr << "DebugModuleManager::instance Failed to create "
403                  << "DebugModuleManager" << endl;
404         }
405         if ( !m_instance->init() ) {
406             cerr << "DebugModuleManager::instance Failed to init "
407                  << "DebugModuleManager" << endl;
408         }
409     }
410     return m_instance;
411 }
412
413 bool
414 DebugModuleManager::registerModule( DebugModule& debugModule )
415 {
416     bool already_present=false;
417
418     for ( DebugModuleVectorIterator it = m_debugModules.begin();
419           it != m_debugModules.end();
420           ++it )
421     {
422         if ( *it == &debugModule ) {
423             already_present=true;
424             return true;
425         }
426     }
427
428     if (already_present) {
429         cerr << "DebugModuleManager::registerModule: Module already registered: "
430             << "DebugModule (" << debugModule.getName() << ")" << endl;
431     } else {
432         m_debugModules.push_back( &debugModule );
433     }
434     return true;
435 }
436
437 bool
438 DebugModuleManager::unregisterModule( DebugModule& debugModule )
439 {
440
441     for ( DebugModuleVectorIterator it = m_debugModules.begin();
442           it != m_debugModules.end();
443           ++it )
444     {
445         if ( *it == &debugModule ) {
446             m_debugModules.erase( it );
447             return true;
448         }
449     }
450
451     cerr << "DebugModuleManager::unregisterModule: Could not unregister "
452          << "DebugModule (" << debugModule.getName() << ")" << endl;
453     return false;
454 }
455
456 bool
457 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
458 {
459     for ( DebugModuleVectorIterator it = m_debugModules.begin();
460           it != m_debugModules.end();
461           ++it )
462     {
463         if ( (*it)->getName() == name ) {
464             return (*it)->setLevel( level );
465         }
466     }
467
468     cerr << "setDebugLevel: Did not find DebugModule ("
469          << name << ")" << endl;
470     return false;
471 }
472
473 void
474 DebugModuleManager::flush()
475 {
476 #if DEBUG_USE_MESSAGE_BUFFER
477     mb_flush();
478 #else
479     fflush(stderr);
480 #endif
481 }
482
483 #if DEBUG_USE_MESSAGE_BUFFER
484 void
485 DebugModuleManager::mb_flush()
486 {
487     /* called WITHOUT the mb_write_lock */
488    
489     /* the flush lock is to allow a flush from multiple threads
490      * this allows a code section that outputs a lot of debug messages
491      * and that can be blocked to flush the buffer itself such that it
492      * does not overflow.
493      */
494     DebugModuleManager *m=DebugModuleManager::instance();
495     pthread_mutex_lock(&m->mb_flush_lock);
496     while (mb_outbuffer != mb_inbuffer) {
497         fputs(mb_buffers[mb_outbuffer], stderr);
498         mb_outbuffer = MB_NEXT(mb_outbuffer);
499     }
500     fflush(stderr);
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     while (m->mb_initialized) {
511         sem_wait(&m->mb_writes);
512         m->mb_flush();
513     }
514
515     return NULL;
516 }
517 #endif
518
519 #if DEBUG_BACKLOG_SUPPORT
520 void
521 DebugModuleManager::showBackLog()
522 {
523      DebugModuleManager *m=DebugModuleManager::instance();
524     // locking the flush lock ensures that the backlog is
525     // printed as one entity
526     pthread_mutex_lock(&m->mb_flush_lock);
527     fprintf(stderr, "=====================================================\n");
528     fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
529     fprintf(stderr, "=====================================================\n");
530
531     for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
532         unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
533         fputs("BL: ", stderr);
534         fputs(bl_mb_buffers[idx], stderr);
535     }
536     fprintf(stderr, "BL: \n");
537
538     fprintf(stderr, "=====================================================\n");
539     fprintf(stderr, "* END OF BACKLOG PRINT\n");
540     fprintf(stderr, "=====================================================\n");
541     pthread_mutex_unlock(&m->mb_flush_lock);
542 }
543
544 void
545 DebugModuleManager::showBackLog(int nblines)
546 {
547      DebugModuleManager *m=DebugModuleManager::instance();
548     // locking the flush lock ensures that the backlog is
549     // printed as one entity
550     pthread_mutex_lock(&m->mb_flush_lock);
551     fprintf(stderr, "=====================================================\n");
552     fprintf(stderr, "* BEGIN OF BACKLOG PRINT\n");
553     fprintf(stderr, "=====================================================\n");
554
555     int lines_to_skip = BACKLOG_MB_BUFFERS - nblines;
556     if (lines_to_skip < 0) lines_to_skip = 0;
557     for (unsigned int i=0; i<BACKLOG_MB_BUFFERS;i++) {
558         if (lines_to_skip-- < 0) {
559             unsigned int idx=(i+bl_mb_inbuffer)%BACKLOG_MB_BUFFERS;
560             fputs("BL: ", stderr);
561             fputs(bl_mb_buffers[idx], stderr);
562         }
563     }
564     fprintf(stderr, "BL: \n");
565
566     fprintf(stderr, "=====================================================\n");
567     fprintf(stderr, "* END OF BACKLOG PRINT\n");
568     fprintf(stderr, "=====================================================\n");
569     pthread_mutex_unlock(&m->mb_flush_lock);
570 }
571
572 void
573 DebugModuleManager::backlog_print(const char *msg)
574 {
575     unsigned int ntries;
576     struct timespec wait = {0, DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NSEC};
577     // the backlog
578     ntries=DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NTRIES;
579     while (ntries) { // try a few times
580         if (pthread_mutex_trylock(&bl_mb_write_lock) == 0) {
581             strncpy(bl_mb_buffers[bl_mb_inbuffer], msg, MB_BUFFERSIZE);
582             bl_mb_inbuffer = BACKLOG_MB_NEXT(bl_mb_inbuffer);
583             pthread_mutex_unlock(&bl_mb_write_lock);
584             break;
585         } else {
586             nanosleep(&wait, NULL);
587             ntries--;
588         }
589     }
590     // just bail out should it have failed
591 }
592 #endif
593
594 void
595 DebugModuleManager::print(const char *msg)
596 {
597 #if DEBUG_USE_MESSAGE_BUFFER
598     unsigned int ntries;
599     struct timespec wait = {0,50000};
600
601     if (!mb_initialized) {
602         /* Unable to print message with realtime safety.
603          * Complain and print it anyway. */
604         fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
605             msg);
606         return;
607     }
608
609     ntries=6;
610     while (ntries) { // try a few times
611         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
612             strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
613             mb_inbuffer = MB_NEXT(mb_inbuffer);
614             sem_post(&mb_writes);
615             pthread_mutex_unlock(&mb_write_lock);
616             break;
617         } else {
618             nanosleep(&wait, NULL);
619             ntries--;
620         }
621     }
622     if (ntries==0) {  /* lock collision */
623         //         atomic_add(&mb_overruns, 1);
624         // FIXME: atomicity
625         mb_overruns++; // skip the atomicness for now
626     }
627 #else
628     fprintf(stderr,msg);
629 #endif
630 }
631
632 #if DEBUG_BACKTRACE_SUPPORT
633 void
634 DebugModuleManager::printBacktrace(int len)
635 {
636     int nptrs;
637     int chars_written=0;
638
639     if(len > DEBUG_MAX_BACKTRACE_LENGTH) {
640         len = DEBUG_MAX_BACKTRACE_LENGTH;
641     }
642
643     pthread_mutex_lock(&m_backtrace_lock);
644     nptrs = backtrace(m_backtrace_buffer, len);
645     chars_written += snprintf(m_backtrace_strbuffer, MB_BUFFERSIZE-chars_written, "BACKTRACE (%d/%d): ", nptrs, len);
646
647     for (int j = 0; j < nptrs; j++) {
648         chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "%p ", m_backtrace_buffer[j]);
649     }
650     chars_written += snprintf(m_backtrace_strbuffer + chars_written, MB_BUFFERSIZE-chars_written, "\n");
651
652     // make sure the string is terminated properly
653     m_backtrace_strbuffer[MB_BUFFERSIZE-2] = '\n';
654     m_backtrace_strbuffer[MB_BUFFERSIZE-1] = 0;
655    
656     // save the pointers to the pointers-seen list such that we can
657     // dump their info later on
658     bool seen;
659     for (int i=0; i<nptrs; i++) {
660         seen = false;
661         int j;
662         for (j=0; j<m_backtrace_buffer_nb_seen & j < DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN; j++) {
663             if(m_backtrace_buffer_seen[j] == m_backtrace_buffer[i]) {
664                 seen = true;
665                 break;
666             }
667         }
668         if (!seen) {
669             m_backtrace_buffer_seen[j] = m_backtrace_buffer[i];
670             m_backtrace_buffer_nb_seen++;
671         }
672     }
673    
674     print(m_backtrace_strbuffer);
675
676     pthread_mutex_unlock(&m_backtrace_lock);
677 }
678
679 void *
680 DebugModuleManager::getBacktracePtr(int id)
681 {
682     int nptrs;
683     void *retval = NULL;
684
685     if(id >= DEBUG_MAX_BACKTRACE_LENGTH) {
686         return NULL;
687     }
688
689     pthread_mutex_lock(&m_backtrace_lock);
690     nptrs = backtrace(m_backtrace_buffer, id+1);
691     if(id<nptrs) {
692         retval = m_backtrace_buffer[id];
693     }
694     pthread_mutex_unlock(&m_backtrace_lock);
695    
696     return retval;
697 }
698 #endif
699
700 //----------------------------------------
701
702 unsigned char
703 toAscii( unsigned char c )
704 {
705     if ( ( c > 31 ) && ( c < 126) ) {
706         return c;
707     } else {
708         return '.';
709     }
710 }
711
712 /* converts a quadlet to a uchar * buffer
713  * not implemented optimally, but clear
714  */
715 void
716 quadlet2char( quadlet_t quadlet, unsigned char* buff )
717 {
718     *(buff)   = (quadlet>>24)&0xFF;
719     *(buff+1) = (quadlet>>16)&0xFF;
720     *(buff+2) = (quadlet>> 8)&0xFF;
721     *(buff+3) = (quadlet)    &0xFF;
722 }
723
724 void
725 hexDump( unsigned char *data_start, unsigned int length )
726 {
727     unsigned int i=0;
728     unsigned int byte_pos;
729     unsigned int bytes_left;
730
731     if ( length <= 0 ) {
732         return;
733     }
734     if ( length >= 7 ) {
735         for ( i = 0; i < (length-7); i += 8 ) {
736             printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
737                     "- [%c%c%c%c%c%c%c%c]\n",
738
739                     i,
740
741                     *(data_start+i+0),
742                     *(data_start+i+1),
743                     *(data_start+i+2),
744                     *(data_start+i+3),
745                     *(data_start+i+4),
746                     *(data_start+i+5),
747                     *(data_start+i+6),
748                     *(data_start+i+7),
749
750                     toAscii( *(data_start+i+0) ),
751                     toAscii( *(data_start+i+1) ),
752                     toAscii( *(data_start+i+2) ),
753                     toAscii( *(data_start+i+3) ),
754                     toAscii( *(data_start+i+4) ),
755                     toAscii( *(data_start+i+5) ),
756                     toAscii( *(data_start+i+6) ),
757                     toAscii( *(data_start+i+7) )
758                 );
759         }
760     }
761     byte_pos = i;
762     bytes_left = length - byte_pos;
763
764     printf( "%04X:" ,i );
765     for ( i = byte_pos; i < length; i += 1 ) {
766         printf( " %02X", *(data_start+i) );
767     }
768     for ( i=0; i < 8-bytes_left; i+=1 ) {
769         printf( "   " );
770     }
771
772     printf( " - [" );
773     for ( i = byte_pos; i < length; i += 1) {
774         printf( "%c", toAscii(*(data_start+i)));
775     }
776     for ( i = 0; i < 8-bytes_left; i += 1) {
777         printf( " " );
778     }
779
780     printf( "]" );
781     printf( "\n" );
782 }
783
784 void
785 hexDumpQuadlets( quadlet_t *data, unsigned int length )
786 {
787     unsigned int i=0;
788
789     if ( length <= 0 ) {
790         return;
791     }
792     for (i = 0; i< length; i += 1) {
793         printf( "%02d %04X: %08X (%08X)"
794                 "\n", i, i*4, data[i],CondSwapFromBus32(data[i]));
795     }
796 }
797
798
Note: See TracBrowser for help on using the browser.