iPXE
debug.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdio.h>
00027 #include <stdint.h>
00028 #include <stdarg.h>
00029 #include <ctype.h>
00030 #include <ipxe/console.h>
00031 
00032 /**
00033  * Print debug message
00034  *
00035  * @v fmt               Format string
00036  * @v ...               Arguments
00037  */
00038 void dbg_printf ( const char *fmt, ... ) {
00039         int saved_usage;
00040         va_list args;
00041 
00042         /* Mark console as in use for debugging messages */
00043         saved_usage = console_set_usage ( CONSOLE_USAGE_DEBUG );
00044 
00045         /* Print message */
00046         va_start ( args, fmt );
00047         vprintf ( fmt, args );
00048         va_end ( args );
00049 
00050         /* Restore console usage */
00051         console_set_usage ( saved_usage );
00052 }
00053 
00054 /**
00055  * Pause until a key is pressed
00056  *
00057  */
00058 void dbg_pause ( void ) {
00059         dbg_printf ( "\nPress a key..." );
00060         getchar();
00061         dbg_printf ( "\r              \r" );
00062 }
00063 
00064 /**
00065  * Indicate more data to follow and pause until a key is pressed
00066  *
00067  */
00068 void dbg_more ( void ) {
00069         dbg_printf ( "---more---" );
00070         getchar();
00071         dbg_printf ( "\r          \r" );
00072 }
00073 
00074 /**
00075  * Print row of a hex dump with specified display address
00076  *
00077  * @v dispaddr          Display address
00078  * @v data              Data to print
00079  * @v len               Length of data
00080  * @v offset            Starting offset within data
00081  */
00082 static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data,
00083                                   unsigned long len, unsigned int offset ) {
00084         const uint8_t *bytes = data;
00085         unsigned int i;
00086         uint8_t byte;
00087 
00088         dbg_printf ( "%08lx :", ( dispaddr + offset ) );
00089         for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
00090                 if ( i >= len ) {
00091                         dbg_printf ( "   " );
00092                         continue;
00093                 }
00094                 dbg_printf ( "%c%02x",
00095                              ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
00096         }
00097         dbg_printf ( " : " );
00098         for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
00099                 if ( i >= len ) {
00100                         dbg_printf ( " " );
00101                         continue;
00102                 }
00103                 byte = bytes[i];
00104                 dbg_printf ( "%c", ( isprint ( byte ) ? byte : '.' ) );
00105         }
00106         dbg_printf ( "\n" );
00107 }
00108 
00109 /**
00110  * Print hex dump with specified display address
00111  *
00112  * @v dispaddr          Display address
00113  * @v data              Data to print
00114  * @v len               Length of data
00115  */
00116 void dbg_hex_dump_da ( unsigned long dispaddr, const void *data,
00117                        unsigned long len ) {
00118         unsigned int offset;
00119 
00120         for ( offset = 0 ; offset < len ; offset += 16 ) {
00121                 dbg_hex_dump_da_row ( dispaddr, data, len, offset );
00122         }
00123 }
00124 
00125 /**
00126  * Base message stream colour
00127  *
00128  * We default to using 31 (red foreground) as the base colour.
00129  */
00130 #ifndef DBGCOL_MIN
00131 #define DBGCOL_MIN 31
00132 #endif
00133 
00134 /**
00135  * Maximum number of separately coloured message streams
00136  *
00137  * Six is the realistic maximum; there are 8 basic ANSI colours, one
00138  * of which will be the terminal default and one of which will be
00139  * invisible on the terminal because it matches the background colour.
00140  */
00141 #ifndef DBGCOL_MAX
00142 #define DBGCOL_MAX ( DBGCOL_MIN + 6 - 1 )
00143 #endif
00144 
00145 /** A colour assigned to an autocolourised debug message stream */
00146 struct autocolour {
00147         /** Message stream ID */
00148         unsigned long stream;
00149         /** Last recorded usage */
00150         unsigned long last_used;
00151 };
00152 
00153 /**
00154  * Choose colour index for debug autocolourisation
00155  *
00156  * @v stream            Message stream ID
00157  * @ret colour          Colour ID
00158  */
00159 static int dbg_autocolour ( unsigned long stream ) {
00160         static struct autocolour acs[ DBGCOL_MAX - DBGCOL_MIN + 1 ];
00161         static unsigned long use;
00162         unsigned int i;
00163         unsigned int oldest;
00164         unsigned int oldest_last_used;
00165 
00166         /* Increment usage iteration counter */
00167         use++;
00168 
00169         /* Scan through list for a currently assigned colour */
00170         for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) {
00171                 if ( acs[i].stream == stream ) {
00172                         acs[i].last_used = use;
00173                         return i;
00174                 }
00175         }
00176 
00177         /* No colour found; evict the oldest from the list */
00178         oldest = 0;
00179         oldest_last_used = use;
00180         for ( i = 0 ; i < ( sizeof ( acs ) / sizeof ( acs[0] ) ) ; i++ ) {
00181                 if ( acs[i].last_used < oldest_last_used ) {
00182                         oldest_last_used = acs[i].last_used;
00183                         oldest = i;
00184                 }
00185         }
00186         acs[oldest].stream = stream;
00187         acs[oldest].last_used = use;
00188         return oldest;
00189 }
00190 
00191 /**
00192  * Select automatic colour for debug messages
00193  *
00194  * @v stream            Message stream ID
00195  */
00196 void dbg_autocolourise ( unsigned long stream ) {
00197 
00198         if ( DBGCOL_MIN ) {
00199                 dbg_printf ( "\033[%dm",
00200                              ( stream ?
00201                                ( DBGCOL_MIN + dbg_autocolour ( stream ) ) : 0));
00202         }
00203 }
00204 
00205 /**
00206  * Revert to normal colour
00207  *
00208  */
00209 void dbg_decolourise ( void ) {
00210 
00211         if ( DBGCOL_MIN )
00212                 dbg_printf ( "\033[0m" );
00213 }