diff --git a/src/core/debug.c b/src/core/debug.c index 9ef25b89..4754bfde 100644 --- a/src/core/debug.c +++ b/src/core/debug.c @@ -15,25 +15,58 @@ void more ( void ) { printf ( "\r \r" ); } -/* Produce a paged hex dump of the specified data and length */ -void hex_dump ( const unsigned char *data, const unsigned int len ) { - unsigned int index; - for ( index = 0; index < len; index++ ) { - if ( ( index % 16 ) == 0 ) { - printf ( "\n" ); +/** + * Print row of a hex dump with specified display address + * + * @v dispaddr Display address + * @v data Data to print + * @v len Length of data + * @v offset Starting offset within data + */ +static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data, + unsigned long len, unsigned int offset ) { + const uint8_t *bytes = data; + unsigned int i; + uint8_t byte; + + printf ( "%08lx :", ( dispaddr + offset ) ); + for ( i = offset ; i < ( offset + 16 ) ; i++ ) { + if ( i >= len ) { + printf ( " " ); + continue; } - if ( ( index % 368 ) == 352 ) { - more(); + printf ( " %02x", bytes[i] ); + } + printf ( " : " ); + for ( i = offset ; i < ( offset + 16 ) ; i++ ) { + if ( i >= len ) { + printf ( " " ); + continue; } - if ( ( index % 16 ) == 0 ) { - printf ( "%p [%lx] : %04x :", data + index, - virt_to_phys ( data + index ), index ); - } - printf ( " %02x", data[index] ); + byte = bytes[i]; + if ( ( byte < 0x20 ) || ( byte >= 0x7f ) ) + byte = '.'; + printf ( "%c", byte ); } printf ( "\n" ); } +/** + * Print hex dump with specified display address + * + * @v dispaddr Display address + * @v data Data to print + * @v len Length of data + */ +void dbg_hex_dump_da ( unsigned long dispaddr, const void *data, + unsigned long len ) { + unsigned int offset; + + for ( offset = 0 ; offset < len ; offset += 16 ) { + dbg_hex_dump_da_row ( dispaddr, data, len, offset ); + } +} + #define GUARD_SYMBOL ( ( 'M' << 24 ) | ( 'I' << 16 ) | ( 'N' << 8 ) | 'E' ) /* Fill a region with guard markers. We use a 4-byte pattern to make * it less likely that check_region will find spurious 1-byte regions @@ -87,14 +120,30 @@ int check_region ( void *region, size_t len ) { return corrupted; } +/** + * Maximum number of separately coloured message streams + * + * Six is the realistic maximum; there are 8 basic ANSI colours, one + * of which will be the terminal default and one of which will be + * invisible on the terminal because it matches the background colour. + */ #define NUM_AUTO_COLOURS 6 +/** A colour assigned to an autocolourised debug message stream */ struct autocolour { - void * id; + /** Message stream ID */ + unsigned long stream; + /** Last recorded usage */ unsigned long last_used; }; -static int autocolourise ( void *id ) { +/** + * Choose colour index for debug autocolourisation + * + * @v stream Message stream ID + * @ret colour Colour ID + */ +static int dbg_autocolour ( unsigned long stream ) { static struct autocolour acs[NUM_AUTO_COLOURS]; static unsigned long use; unsigned int i; @@ -106,7 +155,7 @@ static int autocolourise ( void *id ) { /* Scan through list for a currently assigned colour */ for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) { - if ( acs[i].id == id ) { + if ( acs[i].stream == stream ) { acs[i].last_used = use; return i; } @@ -121,23 +170,25 @@ static int autocolourise ( void *id ) { oldest = i; } } - acs[oldest].id = id; + acs[oldest].stream = stream; acs[oldest].last_used = use; return oldest; } -/** printf() for debugging with automatic colourisation +/** + * Select automatic colour for debug messages * - * @v id Message stream ID - * @v fmt printf() format - * @v ... printf() argument list + * @v stream Message stream ID */ -void dbg_printf_autocolour ( void *id, const char *fmt, ... ) { - va_list args; +void dbg_autocolourise ( unsigned long stream ) { + printf ( "\033[%dm", + ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) ); +} - printf ( "\033[%dm", ( id ? ( 31 + autocolourise ( id ) ) : 0 ) ); - va_start ( args, fmt ); - vprintf ( fmt, args ); - va_end ( args ); +/** + * Revert to normal colour + * + */ +void dbg_decolourise ( void ) { printf ( "\033[0m" ); } diff --git a/src/include/compiler.h b/src/include/compiler.h index 49aaec63..8e5bd87d 100644 --- a/src/include/compiler.h +++ b/src/include/compiler.h @@ -127,8 +127,10 @@ __asm__ ( ".equ\tDBGLVL, " DEBUG_SYMBOL_STR ); extern int __attribute__ (( format ( printf, 1, 2 ) )) dbg_printf ( const char *fmt, ... ) asm ( "printf" ); -extern void __attribute__ (( format ( printf, 2, 3 ) )) -dbg_printf_autocolour ( void *id, const char *fmt, ... ); +extern void dbg_autocolourise ( unsigned long id ); +extern void dbg_decolourise ( void ); +extern void dbg_hex_dump_da ( unsigned long dispaddr, + const void *data, unsigned long len ); /* Compatibility with existing Makefile */ #if DEBUG_SYMBOL >= 1 @@ -146,21 +148,107 @@ dbg_printf_autocolour ( void *id, const char *fmt, ... ); #define DBGLVL_EXTRA 2 #define DBG_EXTRA ( DBGLVL & DBGLVL_EXTRA ) +/** + * Print debugging message if we are at a certain debug level + * + * @v level Debug level + * @v ... printf() argument list + */ #define DBG_IF( level, ... ) do { \ if ( DBG_ ## level ) { \ dbg_printf ( __VA_ARGS__ ); \ } \ } while ( 0 ) -#define DBGC_IF( level, ... ) do { \ +/** + * Print a hex dump if we are at a certain debug level + * + * @v level Debug level + * @v dispaddr Display address + * @v data Data to print + * @v len Length of data + */ +#define DBG_HDA_IF( level, dispaddr, data, len ) do { \ if ( DBG_ ## level ) { \ - dbg_printf_autocolour ( __VA_ARGS__ ); \ + union { \ + unsigned long ul; \ + typeof ( dispaddr ) raw; \ + } da; \ + da.raw = dispaddr; \ + dbg_hex_dump_da ( da.ul, data, len ); \ } \ } while ( 0 ) +/** + * Print a hex dump if we are at a certain debug level + * + * @v level Debug level + * @v data Data to print + * @v len Length of data + */ +#define DBG_HD_IF( level, data, len ) do { \ + DBG_HDA_IF ( level, data, data, len ); \ + } while ( 0 ) + +/** + * Select colour for debug messages if we are at a certain debug level + * + * @v level Debug level + * @v id Message stream ID + */ +#define DBG_AC_IF( level, id ) do { \ + if ( DBG_ ## level ) { \ + union { \ + unsigned long ul; \ + typeof ( id ) raw; \ + } stream; \ + stream.raw = id; \ + dbg_autocolourise ( stream.ul ); \ + } \ + } while ( 0 ) + +/** + * Revert colour for debug messages if we are at a certain debug level + * + * @v level Debug level + */ +#define DBG_DC_IF( level ) do { \ + if ( DBG_ ## level ) { \ + dbg_decolourise(); \ + } \ + } while ( 0 ) + +/* Autocolourising versions of the DBGxxx_IF() macros */ + +#define DBGC_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +#define DBGC_HDA_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_HDA_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +#define DBGC_HD_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_HD_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +/* Versions of the DBGxxx_IF() macros that imply DBGxxx_IF( LOG, ... )*/ + #define DBG( ... ) DBG_IF ( LOG, __VA_ARGS__ ) -#define DBG2( ... ) DBG_IF ( EXTRA, __VA_ARGS__ ) +#define DBG_HDA( ... ) DBG_HDA_IF ( LOG, __VA_ARGS__ ) +#define DBG_HD( ... ) DBG_HD_IF ( LOG, __VA_ARGS__ ) #define DBGC( ... ) DBGC_IF ( LOG, __VA_ARGS__ ) +#define DBGC_HDA( ... ) DBGC_HDA_IF ( LOG, __VA_ARGS__ ) +#define DBGC_HD( ... ) DBGC_HD_IF ( LOG, __VA_ARGS__ ) + +/* Backwards compatibility */ +#define DBG2( ... ) DBG_IF ( EXTRA, __VA_ARGS__ ) #if DEBUG_SYMBOL == 0 #define NDEBUG