2 * Copyright (C) 2005-2008 by Daniel Wagner
3 * Copyright (C) 2005-2008 by Pieter Palmers
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB
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.
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.
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/>.
25 #include "debugmodule.h"
28 #include "libutil/ByteSwap.h"
29 #include "libutil/Time.h"
37 #if DEBUG_BACKTRACE_SUPPORT
44 #if DEBUG_USE_MESSAGE_BUFFER
47 #warning Printing debug info without ringbuffer, not RT-safe!
49 #error Printing debug info without ringbuffer, not RT-safe (not allowed for non-debug builds)!
56 const char* preSequence
;
57 const char* postSequence
;
60 ColorEntry colorTable
[] = {
62 { "\033[31mFatal", "\033[0m" },
63 { "\033[31mError", "\033[0m" },
64 { "\033[31mWarning", "\033[0m" },
69 DebugModule::DebugModule( std::string name
, debug_level_t level
)
73 if ( !DebugModuleManager::instance()->registerModule( *this ) ) {
74 cerr
<< "Could not register DebugModule (" << name
75 << ") at DebugModuleManager"
80 DebugModule::~DebugModule()
82 // if ( m_level >= eDL_VeryVerbose ) {
83 // cout << "Unregistering "
85 // << " at DebugModuleManager"
89 if (m_manager
&& !m_manager
->unregisterModule( *this ) ) {
90 cerr
<< "Could not unregister DebugModule at DebugModuleManager"
97 DebugModule::printShort( debug_level_t level
,
102 // bypass for performance
103 #if DEBUG_BACKLOG_SUPPORT
104 if (level
> BACKLOG_MIN_LEVEL
105 && level
> m_level
) {
109 if ( level
>m_level
) {
114 const char *warning
= "WARNING: message truncated!\n";
115 const int warning_size
= 32;
117 char msg
[MB_BUFFERSIZE
];
119 // format the message such that it remains together
123 va_start( arg
, format
);
124 retval
= vsnprintf(msg
+chars_written
, MB_BUFFERSIZE
, format
, arg
);
126 if (retval
>= 0) { // ignore errors
127 chars_written
+= retval
;
130 // output a warning if the message was truncated
131 if (chars_written
== MB_BUFFERSIZE
) {
132 snprintf(msg
+MB_BUFFERSIZE
-warning_size
, warning_size
, "%s", warning
);
135 #if DEBUG_BACKLOG_SUPPORT
136 // print to backlog if necessary
137 if (level
<= BACKLOG_MIN_LEVEL
) {
138 DebugModuleManager::instance()->backlog_print( msg
);
142 // print to stderr if necessary
143 if ( level
<= m_level
) {
144 DebugModuleManager::instance()->print( msg
);
149 DebugModule::print( debug_level_t level
,
151 const char* function
,
156 // bypass for performance
157 #if DEBUG_BACKLOG_SUPPORT
158 if (level
> BACKLOG_MIN_LEVEL
159 && level
> m_level
) {
163 if ( level
>m_level
) {
168 const char *warning
= "WARNING: message truncated!\n";
169 const int warning_size
= 32;
172 char msg
[MB_BUFFERSIZE
];
174 // remove the path info from the filename
175 const char *f
= file
;
176 const char *fname
= file
;
177 while((f
=strstr(f
, "/"))) {
178 f
++; // move away from delimiter
182 // add a timing timestamp
184 Util::SystemTimeSource::clockGettime(&ts
);
185 uint64_t ts_usec
=(uint64_t)(ts
.tv_sec
* 1000000LL + ts
.tv_nsec
/ 1000LL);
187 // format the message such that it remains together
190 retval
= snprintf(msg
, MB_BUFFERSIZE
, "%011"PRIu64
": %s (%s)[%4u] %s: ",
191 ts_usec
, getPreSequence( level
),
192 fname
, line
, function
);
193 if (retval
>= 0) chars_written
+= retval
; // ignore errors
195 va_start( arg
, format
);
196 retval
= vsnprintf( msg
+ chars_written
,
197 MB_BUFFERSIZE
- chars_written
,
200 if (retval
>= 0) chars_written
+= retval
; // ignore errors
202 retval
= snprintf( msg
+ chars_written
,
203 MB_BUFFERSIZE
- chars_written
,
204 "%s", getPostSequence( level
) );
205 if (retval
>= 0) chars_written
+= retval
; // ignore errors
207 // output a warning if the message was truncated
208 if (chars_written
== MB_BUFFERSIZE
) {
209 snprintf(msg
+ MB_BUFFERSIZE
- warning_size
,
214 #if DEBUG_BACKLOG_SUPPORT
215 // print to backlog if necessary
216 if (level
<= BACKLOG_MIN_LEVEL
) {
217 DebugModuleManager::instance()->backlog_print( msg
);
221 // print to stderr if necessary
222 if ( level
<= m_level
) {
223 DebugModuleManager::instance()->print( msg
);
228 DebugModule::getPreSequence( debug_level_t level
) const
230 if ( ( level
<= eDL_Normal
) && ( level
>= eDL_Message
) ) {
231 return colorTable
[level
].preSequence
;
233 return colorTable
[eDL_Normal
].preSequence
;
237 DebugModule::getPostSequence( debug_level_t level
) const
239 if ( ( level
<= eDL_Normal
) && ( level
>= eDL_Message
) ) {
240 return colorTable
[level
].postSequence
;
242 return colorTable
[eDL_Normal
].postSequence
;
245 //--------------------------------------
247 DebugModuleManager
* DebugModuleManager::m_instance
= 0;
249 DebugModuleManager::DebugModuleManager()
251 #if DEBUG_USE_MESSAGE_BUFFER
256 #if DEBUG_BACKTRACE_SUPPORT
257 , m_backtrace_buffer_nb_seen(0)
259 #if DEBUG_BACKLOG_SUPPORT
266 DebugModuleManager::~DebugModuleManager()
268 // cleaning up leftover modules
269 while (!m_debugModules
.empty())
271 DebugModule
*mod
= m_debugModules
.back();
272 unregisterModule(*mod
);
278 #if DEBUG_USE_MESSAGE_BUFFER
279 pthread_mutex_lock(&mb_write_lock
);
281 sem_post(&mb_writes
);
282 pthread_mutex_unlock(&mb_write_lock
);
284 pthread_join(mb_writer_thread
, NULL
);
288 #if DEBUG_BACKTRACE_SUPPORT
289 pthread_mutex_lock(&m_backtrace_lock
);
290 // print a list of the symbols seen in a backtrace
291 fprintf(stderr
, "Backtrace saw %d symbols:\n", m_backtrace_buffer_nb_seen
);
292 char **strings
= backtrace_symbols(m_backtrace_buffer_seen
, m_backtrace_buffer_nb_seen
);
293 if (strings
== NULL
) {
294 perror("backtrace_symbols");
300 for (int j
= 0; j
< m_backtrace_buffer_nb_seen
; j
++) {
301 if (dladdr(m_backtrace_buffer_seen
[j
], &info
) != 0) {
302 outbuf
= __cxxabiv1::__cxa_demangle(info
.dli_sname
, outbuf
, &length
, &status
);
303 if(outbuf
&& status
== 0) {
304 fprintf(stderr
, " %p => %s\n",
305 m_backtrace_buffer_seen
[j
], outbuf
);
309 fprintf(stderr
, " %p => %s (demangle status: %d)\n",
310 m_backtrace_buffer_seen
[j
], strings
[j
], status
);
313 fprintf(stderr
, " %p => %s\n",
314 m_backtrace_buffer_seen
[j
], strings
[j
]);
319 pthread_mutex_unlock(&m_backtrace_lock
);
322 #if DEBUG_USE_MESSAGE_BUFFER
324 fprintf(stderr
, "WARNING: %d message buffer overruns!\n",
327 fprintf(stderr
, "no message buffer overruns\n");
329 pthread_mutex_destroy(&mb_write_lock
);
330 sem_destroy(&mb_writes
);
333 #if DEBUG_BACKTRACE_SUPPORT
334 pthread_mutex_destroy(&m_backtrace_lock
);
337 #if DEBUG_BACKLOG_SUPPORT
338 pthread_mutex_destroy(&bl_mb_write_lock
);
344 DebugModuleManager::init()
349 // if ( m_level >= eDL_VeryVerbose )
350 // cout << "DebugModuleManager init..." << endl;
352 #if DEBUG_BACKTRACE_SUPPORT
353 pthread_mutex_init(&m_backtrace_lock
, NULL
);
356 #if DEBUG_BACKLOG_SUPPORT
357 pthread_mutex_init(&bl_mb_write_lock
, NULL
);
360 #if DEBUG_USE_MESSAGE_BUFFER
361 pthread_mutex_init(&mb_flush_lock
, NULL
);
362 pthread_mutex_init(&mb_write_lock
, NULL
);
363 sem_init(&mb_writes
, 0, 0);
368 #if DEBUG_MESSAGE_BUFFER_REALTIME
369 /* Get the client thread to run as an RT-FIFO
370 scheduled thread of appropriate priority.
372 pthread_attr_t attributes
;
373 struct sched_param rt_param
;
374 pthread_attr_init(&attributes
);
375 if ((res
= pthread_attr_setinheritsched(&attributes
, PTHREAD_EXPLICIT_SCHED
))) {
376 fprintf(stderr
, "Cannot request explicit scheduling for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
379 if ((res
= pthread_attr_setdetachstate(&attributes
, PTHREAD_CREATE_JOINABLE
))) {
380 fprintf(stderr
, "Cannot request joinable thread creation for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
383 if ((res
= pthread_attr_setscope(&attributes
, PTHREAD_SCOPE_SYSTEM
))) {
384 fprintf(stderr
, "Cannot set scheduling scope for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
388 if ((res
= pthread_attr_setschedpolicy(&attributes
, SCHED_FIFO
))) {
390 //if ((res = pthread_attr_setschedpolicy(&attributes, SCHED_RR))) {
391 fprintf(stderr
, "Cannot set FIFO scheduling class for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
395 memset(&rt_param
, 0, sizeof(rt_param
));
396 rt_param
.sched_priority
= DEBUG_MESSAGE_BUFFER_REALTIME_PRIO
;
398 if ((res
= pthread_attr_setschedparam(&attributes
, &rt_param
))) {
399 fprintf(stderr
, "Cannot set scheduling priority for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
403 mb_initialized
= 1; // set to 1 otherwise the thread might exit (race condition)
404 if ((res
= pthread_create(&mb_writer_thread
, &attributes
, mb_thread_func
, (void *)this))) {
405 fprintf(stderr
, "Cannot create RT messagebuffer thread: %s (%d)\n", strerror(res
), res
);
409 if (res
==EPERM
&& mb_initialized
==0) {
410 fprintf(stderr
, "Retrying messagebuffer thread without RT scheduling\n");
411 memset(&rt_param
, 0, sizeof(rt_param
));
412 if ((res
=pthread_attr_setschedpolicy(&attributes
, SCHED_OTHER
)) ||
413 (res
=pthread_attr_setschedparam(&attributes
, &rt_param
))) {
414 fprintf(stderr
, "Cannot set standard scheduling for messagebuffer thread: %s (%d)\n", strerror(res
), res
);
416 mb_initialized
= 1; // set to 1 otherwise the thread might exit (race condition)
417 if ((res
= pthread_create(&mb_writer_thread
, &attributes
, mb_thread_func
, (void *)this))) {
418 fprintf(stderr
, "Cannot create messagebuffer thread: %s (%d)\n", strerror(res
), res
);
421 fprintf(stderr
, "Messagebuffer not realtime; consider enabling RT scheduling for user\n");
425 mb_initialized
= 1; // set to 1 otherwise the thread might exit (race condition)
426 if ((res
= pthread_create(&mb_writer_thread
, NULL
, &mb_thread_func
, (void *)this))) {
427 fprintf(stderr
, "Cannot create thread %d %s\n", res
, strerror(res
));
437 DebugModuleManager::instance()
440 m_instance
= new DebugModuleManager
;
442 cerr
<< "DebugModuleManager::instance Failed to create "
443 << "DebugModuleManager" << endl
;
445 if ( !m_instance
->init() ) {
446 cerr
<< "DebugModuleManager::instance Failed to init "
447 << "DebugModuleManager" << endl
;
454 DebugModuleManager::registerModule( DebugModule
& debugModule
)
456 bool already_present
=false;
458 for ( DebugModuleVectorIterator it
= m_debugModules
.begin();
459 it
!= m_debugModules
.end();
462 if ( *it
== &debugModule
) {
463 already_present
=true;
468 if (already_present
) {
469 cerr
<< "DebugModuleManager::registerModule: Module already registered: "
470 << "DebugModule (" << debugModule
.getName() << ")" << endl
;
472 m_debugModules
.push_back( &debugModule
);
473 if (debugModule
.m_manager
== NULL
)
474 debugModule
.m_manager
= this;
480 DebugModuleManager::unregisterModule( DebugModule
& debugModule
)
483 for ( DebugModuleVectorIterator it
= m_debugModules
.begin();
484 it
!= m_debugModules
.end();
487 if ( *it
== &debugModule
) {
488 m_debugModules
.erase( it
);
489 if (debugModule
.m_manager
== this)
490 debugModule
.m_manager
= NULL
;
495 cerr
<< "DebugModuleManager::unregisterModule: Could not unregister "
496 << "DebugModule (" << debugModule
.getName() << ")" << endl
;
501 DebugModuleManager::setMgrDebugLevel( std::string name
, debug_level_t level
)
503 for ( DebugModuleVectorIterator it
= m_debugModules
.begin();
504 it
!= m_debugModules
.end();
507 if ( (*it
)->getName() == name
) {
508 return (*it
)->setLevel( level
);
512 cerr
<< "setDebugLevel: Did not find DebugModule ("
513 << name
<< ")" << endl
;
518 DebugModuleManager::flush()
520 #if DEBUG_USE_MESSAGE_BUFFER
527 #if DEBUG_USE_MESSAGE_BUFFER
529 DebugModuleManager::mb_flush()
531 /* called WITHOUT the mb_write_lock */
533 /* the flush lock is to allow a flush from multiple threads
534 * this allows a code section that outputs a lot of debug messages
535 * and that can be blocked to flush the buffer itself such that it
538 DebugModuleManager
*m
=DebugModuleManager::instance();
539 pthread_mutex_lock(&m
->mb_flush_lock
);
540 while (mb_outbuffer
!= mb_inbuffer
) {
541 fputs(mb_buffers
[mb_outbuffer
], stderr
);
542 mb_outbuffer
= MB_NEXT(mb_outbuffer
);
545 pthread_mutex_unlock(&m
->mb_flush_lock
);
549 DebugModuleManager::mb_thread_func(void *arg
)
552 DebugModuleManager
*m
=static_cast<DebugModuleManager
*>(arg
);
554 while (m
->mb_initialized
) {
555 sem_wait(&m
->mb_writes
);
563 #if DEBUG_BACKLOG_SUPPORT
565 DebugModuleManager::showBackLog()
567 DebugModuleManager
*m
=DebugModuleManager::instance();
568 // locking the flush lock ensures that the backlog is
569 // printed as one entity
570 pthread_mutex_lock(&m
->mb_flush_lock
);
571 fprintf(stderr
, "=====================================================\n");
572 fprintf(stderr
, "* BEGIN OF BACKLOG PRINT\n");
573 fprintf(stderr
, "=====================================================\n");
575 for (unsigned int i
=0; i
<BACKLOG_MB_BUFFERS
;i
++) {
576 unsigned int idx
=(i
+bl_mb_inbuffer
)%BACKLOG_MB_BUFFERS
;
577 fputs("BL: ", stderr
);
578 fputs(bl_mb_buffers
[idx
], stderr
);
580 fprintf(stderr
, "BL: \n");
582 fprintf(stderr
, "=====================================================\n");
583 fprintf(stderr
, "* END OF BACKLOG PRINT\n");
584 fprintf(stderr
, "=====================================================\n");
585 pthread_mutex_unlock(&m
->mb_flush_lock
);
589 DebugModuleManager::showBackLog(int nblines
)
591 DebugModuleManager
*m
=DebugModuleManager::instance();
592 // locking the flush lock ensures that the backlog is
593 // printed as one entity
594 pthread_mutex_lock(&m
->mb_flush_lock
);
595 fprintf(stderr
, "=====================================================\n");
596 fprintf(stderr
, "* BEGIN OF BACKLOG PRINT\n");
597 fprintf(stderr
, "=====================================================\n");
599 int lines_to_skip
= BACKLOG_MB_BUFFERS
- nblines
;
600 if (lines_to_skip
< 0) lines_to_skip
= 0;
601 for (unsigned int i
=0; i
<BACKLOG_MB_BUFFERS
;i
++) {
602 if (lines_to_skip
-- < 0) {
603 unsigned int idx
=(i
+bl_mb_inbuffer
)%BACKLOG_MB_BUFFERS
;
604 fputs("BL: ", stderr
);
605 fputs(bl_mb_buffers
[idx
], stderr
);
608 fprintf(stderr
, "BL: \n");
610 fprintf(stderr
, "=====================================================\n");
611 fprintf(stderr
, "* END OF BACKLOG PRINT\n");
612 fprintf(stderr
, "=====================================================\n");
613 pthread_mutex_unlock(&m
->mb_flush_lock
);
617 DebugModuleManager::backlog_print(const char *msg
)
620 struct timespec wait
= {0, DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NSEC
};
622 ntries
=DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NTRIES
;
623 while (ntries
) { // try a few times
624 if (pthread_mutex_trylock(&bl_mb_write_lock
) == 0) {
625 strncpy(bl_mb_buffers
[bl_mb_inbuffer
], msg
, MB_BUFFERSIZE
);
626 bl_mb_inbuffer
= BACKLOG_MB_NEXT(bl_mb_inbuffer
);
627 pthread_mutex_unlock(&bl_mb_write_lock
);
630 nanosleep(&wait
, NULL
);
634 // just bail out should it have failed
639 DebugModuleManager::print(const char *msg
)
641 #if DEBUG_USE_MESSAGE_BUFFER
643 struct timespec wait
= {0,50000};
645 if (!mb_initialized
) {
646 /* Unable to print message with realtime safety.
647 * Complain and print it anyway. */
648 fprintf(stderr
, "ERROR: messagebuffer not initialized: %s",
654 while (ntries
) { // try a few times
655 if (pthread_mutex_trylock(&mb_write_lock
) == 0) {
656 strncpy(mb_buffers
[mb_inbuffer
], msg
, MB_BUFFERSIZE
);
657 mb_inbuffer
= MB_NEXT(mb_inbuffer
);
658 sem_post(&mb_writes
);
659 pthread_mutex_unlock(&mb_write_lock
);
662 nanosleep(&wait
, NULL
);
666 if (ntries
==0) { /* lock collision */
667 // atomic_add(&mb_overruns, 1);
669 mb_overruns
++; // skip the atomicness for now
676 #if DEBUG_BACKTRACE_SUPPORT
678 DebugModuleManager::printBacktrace(int len
)
683 if(len
> DEBUG_MAX_BACKTRACE_LENGTH
) {
684 len
= DEBUG_MAX_BACKTRACE_LENGTH
;
687 pthread_mutex_lock(&m_backtrace_lock
);
688 nptrs
= backtrace(m_backtrace_buffer
, len
);
689 chars_written
+= snprintf(m_backtrace_strbuffer
, MB_BUFFERSIZE
-chars_written
, "BACKTRACE (%d/%d): ", nptrs
, len
);
691 for (int j
= 0; j
< nptrs
; j
++) {
694 getFunctionName(m_backtrace_buffer
[j
], name
, 64);
695 chars_written
+= snprintf(m_backtrace_strbuffer
+ chars_written
, MB_BUFFERSIZE
-chars_written
, "%s\n", name
);
697 chars_written
+= snprintf(m_backtrace_strbuffer
+ chars_written
, MB_BUFFERSIZE
-chars_written
, "\n");
699 // make sure the string is terminated properly
700 m_backtrace_strbuffer
[MB_BUFFERSIZE
-2] = '\n';
701 m_backtrace_strbuffer
[MB_BUFFERSIZE
-1] = 0;
703 // save the pointers to the pointers-seen list such that we can
704 // dump their info later on
706 for (int i
=0; i
<nptrs
; i
++) {
709 for (j
=0; j
<m_backtrace_buffer_nb_seen
&& j
< DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN
; j
++) {
710 if(m_backtrace_buffer_seen
[j
] == m_backtrace_buffer
[i
]) {
716 && j
< DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN
) {
717 m_backtrace_buffer_seen
[j
] = m_backtrace_buffer
[i
];
718 m_backtrace_buffer_nb_seen
++;
722 print(m_backtrace_strbuffer
);
724 pthread_mutex_unlock(&m_backtrace_lock
);
728 DebugModuleManager::getBacktracePtr(int id
)
733 if(id
>= DEBUG_MAX_BACKTRACE_LENGTH
) {
737 pthread_mutex_lock(&m_backtrace_lock
);
738 nptrs
= backtrace(m_backtrace_buffer
, id
+1);
742 retval
= m_backtrace_buffer
[id
];
743 // save the pointers to the pointers-seen list such that we can
744 // dump their info later on
747 for (j
=0; j
<m_backtrace_buffer_nb_seen
&& j
< DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN
; j
++) {
748 if(m_backtrace_buffer_seen
[j
] == m_backtrace_buffer
[id
]) {
754 && j
< DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN
) {
755 m_backtrace_buffer_seen
[j
] = m_backtrace_buffer
[id
];
756 m_backtrace_buffer_nb_seen
++;
758 pthread_mutex_unlock(&m_backtrace_lock
);
764 DebugModuleManager::getFunctionName(void *ptr
, char *buff
, int len
)
770 if (dladdr(ptr
, &info
) != 0) {
771 outbuf
= abi::__cxa_demangle(info
.dli_sname
, outbuf
, &length
, &status
);
772 if(outbuf
&& status
== 0) {
773 if(len
< (int)length
) {
774 strncpy(buff
, outbuf
, len
);
776 strncpy(buff
, outbuf
, length
);
779 snprintf(buff
, len
, "%p (%s)", ptr
, info
.dli_sname
);
782 snprintf(buff
, len
, "%p (I-ERR)", ptr
);
784 if (outbuf
) free(outbuf
);
789 //----------------------------------------
792 toAscii( unsigned char c
)
794 if ( ( c
> 31 ) && ( c
< 126) ) {
801 /* converts a quadlet to a uchar * buffer
802 * not implemented optimally, but clear
805 quadlet2char( quadlet_t quadlet
, unsigned char* buff
)
807 *(buff
) = (quadlet
>>24)&0xFF;
808 *(buff
+1) = (quadlet
>>16)&0xFF;
809 *(buff
+2) = (quadlet
>> 8)&0xFF;
810 *(buff
+3) = (quadlet
) &0xFF;
814 hexDump( unsigned char *data_start
, unsigned int length
)
817 unsigned int byte_pos
;
818 unsigned int bytes_left
;
824 for ( i
= 0; i
< (length
-7); i
+= 8 ) {
825 printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
826 "- [%c%c%c%c%c%c%c%c]\n",
839 toAscii( *(data_start
+i
+0) ),
840 toAscii( *(data_start
+i
+1) ),
841 toAscii( *(data_start
+i
+2) ),
842 toAscii( *(data_start
+i
+3) ),
843 toAscii( *(data_start
+i
+4) ),
844 toAscii( *(data_start
+i
+5) ),
845 toAscii( *(data_start
+i
+6) ),
846 toAscii( *(data_start
+i
+7) )
851 bytes_left
= length
- byte_pos
;
853 printf( "%04X:" ,i
);
854 for ( i
= byte_pos
; i
< length
; i
+= 1 ) {
855 printf( " %02X", *(data_start
+i
) );
857 for ( i
=0; i
< 8-bytes_left
; i
+=1 ) {
862 for ( i
= byte_pos
; i
< length
; i
+= 1) {
863 printf( "%c", toAscii(*(data_start
+i
)));
865 for ( i
= 0; i
< 8-bytes_left
; i
+= 1) {
874 hexDumpQuadlets( quadlet_t
*data
, unsigned int length
)
881 for (i
= 0; i
< length
; i
+= 1) {
882 fprintf(stderr
, "%02d %04X: %08X (%08X)"
883 "\n", i
, i
*4, data
[i
],CondSwapFromBus32(data
[i
]));