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
);
24 #include <gpxe/init.h>
25 #include <gpxe/uaccess.h>
29 * Function trace recorder for crash and hang debugging
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 ),
43 /** Constant for identifying valid trace buffers */
46 /** Next trace buffer entry to fill */
49 /** Function address trace buffer */
50 unsigned long data
[fnrec_buffer_length
];
53 /** The trace buffer */
54 static struct fnrec_buffer
*fnrec_buffer
;
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
;
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
;
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 */
86 fnrec_buffer
->data
[idx
] = l
;
87 fnrec_buffer
->idx
= ( idx
+ 1 ) % fnrec_buffer_length
;
92 * Print the contents of the trace buffer in chronological order
94 static void fnrec_dump ( void ) {
97 if ( !fnrec_is_valid() ) {
98 printf ( "fnrec buffer not found\n" );
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 );
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
) {