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 }
1.5.7.1