fnrec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010 Stefan Hajnoczi <stefanha@gmail.com>.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <gpxe/init.h>
00025 #include <gpxe/uaccess.h>
00026 
00027 /** @file
00028  *
00029  * Function trace recorder for crash and hang debugging
00030  *
00031  */
00032 
00033 enum {
00034         /** Constant for identifying valid trace buffers */
00035         fnrec_magic = 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e',
00036 
00037         /** Trace buffer length */
00038         fnrec_buffer_length = 4096 / sizeof ( unsigned long ),
00039 };
00040 
00041 /** A trace buffer */
00042 struct fnrec_buffer {
00043         /** Constant for identifying valid trace buffers */
00044         uint32_t magic;
00045 
00046         /** Next trace buffer entry to fill */
00047         uint32_t idx;
00048 
00049         /** Function address trace buffer */
00050         unsigned long data[fnrec_buffer_length];
00051 };
00052 
00053 /** The trace buffer */
00054 static struct fnrec_buffer *fnrec_buffer;
00055 
00056 /**
00057  * Test whether the trace buffer is valid
00058  *
00059  * @ret is_valid        Buffer is valid
00060  */
00061 static int fnrec_is_valid ( void ) {
00062         return fnrec_buffer && fnrec_buffer->magic == fnrec_magic;
00063 }
00064 
00065 /**
00066  * Reset the trace buffer and clear entries
00067  */
00068 static void fnrec_reset ( void ) {
00069         memset ( fnrec_buffer, 0, sizeof ( *fnrec_buffer ) );
00070         fnrec_buffer->magic = fnrec_magic;
00071 }
00072 
00073 /**
00074  * Write a value to the end of the buffer if it is not a repetition
00075  *
00076  * @v l                 Value to append
00077  */
00078 static void fnrec_append_unique ( unsigned long l ) {
00079         static unsigned long lastval;
00080         uint32_t idx = fnrec_buffer->idx;
00081 
00082         /* Avoid recording the same value repeatedly */
00083         if ( l == lastval )
00084                 return;
00085 
00086         fnrec_buffer->data[idx] = l;
00087         fnrec_buffer->idx = ( idx + 1 ) % fnrec_buffer_length;
00088         lastval = l;
00089 }
00090 
00091 /**
00092  * Print the contents of the trace buffer in chronological order
00093  */
00094 static void fnrec_dump ( void ) {
00095         size_t i;
00096 
00097         if ( !fnrec_is_valid() ) {
00098                 printf ( "fnrec buffer not found\n" );
00099                 return;
00100         }
00101 
00102         printf ( "fnrec buffer dump:\n" );
00103         for ( i = 0; i < fnrec_buffer_length; i++ ) {
00104                 unsigned long l = fnrec_buffer->data[
00105                         ( fnrec_buffer->idx + i ) % fnrec_buffer_length];
00106                 printf ( "%08lx%c", l, i % 8 == 7 ? '\n' : ' ' );
00107         }
00108 }
00109 
00110 /**
00111  * Function tracer initialisation function
00112  */
00113 static void fnrec_init ( void ) {
00114         /* Hardcoded to 17 MB */
00115         fnrec_buffer = phys_to_virt ( 17 * 1024 * 1024 );
00116         fnrec_dump();
00117         fnrec_reset();
00118 }
00119 
00120 struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = {
00121         .initialise = fnrec_init,
00122 };
00123 
00124 /*
00125  * These functions are called from every C function.  The compiler inserts
00126  * these calls when -finstrument-functions is used.
00127  */
00128 void __cyg_profile_func_enter ( void *called_fn, void *call_site __unused ) {
00129         if ( fnrec_is_valid() )
00130                 fnrec_append_unique ( ( unsigned long ) called_fn );
00131 }
00132 
00133 void __cyg_profile_func_exit ( void *called_fn __unused, void *call_site __unused ) {
00134 }

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1