[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / core / fnrec.c
blobc768c91d4300ba08995fd77ad41028aa5b315f3a
1 /*
2 * Copyright (C) 2010 Stefan Hajnoczi <stefanha@gmail.com>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <gpxe/init.h>
25 #include <gpxe/uaccess.h>
27 /** @file
29 * Function trace recorder for crash and hang debugging
33 enum {
34 /** Constant for identifying valid trace buffers */
35 fnrec_magic = 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e',
37 /** Trace buffer length */
38 fnrec_buffer_length = 4096 / sizeof ( unsigned long ),
41 /** A trace buffer */
42 struct fnrec_buffer {
43 /** Constant for identifying valid trace buffers */
44 uint32_t magic;
46 /** Next trace buffer entry to fill */
47 uint32_t idx;
49 /** Function address trace buffer */
50 unsigned long data[fnrec_buffer_length];
53 /** The trace buffer */
54 static struct fnrec_buffer *fnrec_buffer;
56 /**
57 * Test whether the trace buffer is valid
59 * @ret is_valid Buffer is valid
61 static int fnrec_is_valid ( void ) {
62 return fnrec_buffer && fnrec_buffer->magic == fnrec_magic;
65 /**
66 * Reset the trace buffer and clear entries
68 static void fnrec_reset ( void ) {
69 memset ( fnrec_buffer, 0, sizeof ( *fnrec_buffer ) );
70 fnrec_buffer->magic = fnrec_magic;
73 /**
74 * Write a value to the end of the buffer if it is not a repetition
76 * @v l Value to append
78 static void fnrec_append_unique ( unsigned long l ) {
79 static unsigned long lastval;
80 uint32_t idx = fnrec_buffer->idx;
82 /* Avoid recording the same value repeatedly */
83 if ( l == lastval )
84 return;
86 fnrec_buffer->data[idx] = l;
87 fnrec_buffer->idx = ( idx + 1 ) % fnrec_buffer_length;
88 lastval = l;
91 /**
92 * Print the contents of the trace buffer in chronological order
94 static void fnrec_dump ( void ) {
95 size_t i;
97 if ( !fnrec_is_valid() ) {
98 printf ( "fnrec buffer not found\n" );
99 return;
102 printf ( "fnrec buffer dump:\n" );
103 for ( i = 0; i < fnrec_buffer_length; i++ ) {
104 unsigned long l = fnrec_buffer->data[
105 ( fnrec_buffer->idx + i ) % fnrec_buffer_length];
106 printf ( "%08lx%c", l, i % 8 == 7 ? '\n' : ' ' );
111 * Function tracer initialisation function
113 static void fnrec_init ( void ) {
114 /* Hardcoded to 17 MB */
115 fnrec_buffer = phys_to_virt ( 17 * 1024 * 1024 );
116 fnrec_dump();
117 fnrec_reset();
120 struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = {
121 .initialise = fnrec_init,
125 * These functions are called from every C function. The compiler inserts
126 * these calls when -finstrument-functions is used.
128 void __cyg_profile_func_enter ( void *called_fn, void *call_site __unused ) {
129 if ( fnrec_is_valid() )
130 fnrec_append_unique ( ( unsigned long ) called_fn );
133 void __cyg_profile_func_exit ( void *called_fn __unused, void *call_site __unused ) {