Sfoglia il codice sorgente

[fnrec] Add function recorder for debugging

The function recorder is a crash and hang debugging tool.  It logs each
function call into a memory buffer while gPXE runs.  After the machine
is reset, and if the contents of memory have not been overwritten, gPXE
will detect the memory buffer and print out its contents.

This allows developers to see a trace of the last functions called
before a crash or hang.  The util/fnrec.sh script can be used to convert
the function addresses back into symbol names.

To build with fnrec:

    make FNREC=1

Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.20.1
Stefan Hajnoczi 15 anni fa
parent
commit
6a6f26f74d
3 ha cambiato i file con 195 aggiunte e 0 eliminazioni
  1. 29
    0
      src/Makefile.housekeeping
  2. 134
    0
      src/core/fnrec.c
  3. 32
    0
      src/util/fnrec.sh

+ 29
- 0
src/Makefile.housekeeping Vedi File

@@ -375,6 +375,35 @@ CFLAGS		+= -Werror
375 375
 ASFLAGS		+= --fatal-warnings
376 376
 endif
377 377
 
378
+# Function trace recorder state in the last build.  This is needed
379
+# in order to correctly rebuild whenever the function recorder is
380
+# enabled/disabled.
381
+#
382
+FNREC_STATE	:= $(BIN)/.fnrec.state
383
+ifeq ($(wildcard $(FNREC_STATE)),)
384
+FNREC_STATE_OLD := <invalid>
385
+else
386
+FNREC_STATE_OLD	:= $(shell cat $(FNREC_STATE))
387
+endif
388
+ifeq ($(FNREC_STATE_OLD),$(FNREC))
389
+$(FNREC_STATE) :
390
+else
391
+$(FNREC_STATE) : clean
392
+$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
393
+endif
394
+
395
+VERYCLEANUP	+= $(FNREC_STATE)
396
+MAKEDEPS	+= $(FNREC_STATE)
397
+
398
+ifeq ($(FNREC),1)
399
+# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
400
+# warnings about use of uninitialised variables.
401
+#
402
+CFLAGS		+= -Wno-uninitialized
403
+CFLAGS		+= -finstrument-functions
404
+CFLAGS		+= -finstrument-functions-exclude-file-list=core/fnrec.c
405
+endif
406
+
378 407
 # compiler.h is needed for our linking and debugging system
379 408
 #
380 409
 CFLAGS		+= -include compiler.h

+ 134
- 0
src/core/fnrec.c Vedi File

@@ -0,0 +1,134 @@
1
+/*
2
+ * Copyright (C) 2010 Stefan Hajnoczi <stefanha@gmail.com>.
3
+ *
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.
8
+ *
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.
13
+ *
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.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdlib.h>
22
+#include <stdio.h>
23
+#include <string.h>
24
+#include <gpxe/init.h>
25
+#include <gpxe/uaccess.h>
26
+
27
+/** @file
28
+ *
29
+ * Function trace recorder for crash and hang debugging
30
+ *
31
+ */
32
+
33
+enum {
34
+	/** Constant for identifying valid trace buffers */
35
+	fnrec_magic = 'f' << 24 | 'n' << 16 | 'r' << 8 | 'e',
36
+
37
+	/** Trace buffer length */
38
+	fnrec_buffer_length = 4096 / sizeof ( unsigned long ),
39
+};
40
+
41
+/** A trace buffer */
42
+struct fnrec_buffer {
43
+	/** Constant for identifying valid trace buffers */
44
+	uint32_t magic;
45
+
46
+	/** Next trace buffer entry to fill */
47
+	uint32_t idx;
48
+
49
+	/** Function address trace buffer */
50
+	unsigned long data[fnrec_buffer_length];
51
+};
52
+
53
+/** The trace buffer */
54
+static struct fnrec_buffer *fnrec_buffer;
55
+
56
+/**
57
+ * Test whether the trace buffer is valid
58
+ *
59
+ * @ret is_valid	Buffer is valid
60
+ */
61
+static int fnrec_is_valid ( void ) {
62
+	return fnrec_buffer && fnrec_buffer->magic == fnrec_magic;
63
+}
64
+
65
+/**
66
+ * Reset the trace buffer and clear entries
67
+ */
68
+static void fnrec_reset ( void ) {
69
+	memset ( fnrec_buffer, 0, sizeof ( *fnrec_buffer ) );
70
+	fnrec_buffer->magic = fnrec_magic;
71
+}
72
+
73
+/**
74
+ * Write a value to the end of the buffer if it is not a repetition
75
+ *
76
+ * @v l			Value to append
77
+ */
78
+static void fnrec_append_unique ( unsigned long l ) {
79
+	static unsigned long lastval;
80
+	uint32_t idx = fnrec_buffer->idx;
81
+
82
+	/* Avoid recording the same value repeatedly */
83
+	if ( l == lastval )
84
+		return;
85
+
86
+	fnrec_buffer->data[idx] = l;
87
+	fnrec_buffer->idx = ( idx + 1 ) % fnrec_buffer_length;
88
+	lastval = l;
89
+}
90
+
91
+/**
92
+ * Print the contents of the trace buffer in chronological order
93
+ */
94
+static void fnrec_dump ( void ) {
95
+	size_t i;
96
+
97
+	if ( !fnrec_is_valid() ) {
98
+		printf ( "fnrec buffer not found\n" );
99
+		return;
100
+	}
101
+
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' : ' ' );
107
+	}
108
+}
109
+
110
+/**
111
+ * Function tracer initialisation function
112
+ */
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();
118
+}
119
+
120
+struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = {
121
+	.initialise = fnrec_init,
122
+};
123
+
124
+/*
125
+ * These functions are called from every C function.  The compiler inserts
126
+ * these calls when -finstrument-functions is used.
127
+ */
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 );
131
+}
132
+
133
+void __cyg_profile_func_exit ( void *called_fn __unused, void *call_site __unused ) {
134
+}

+ 32
- 0
src/util/fnrec.sh Vedi File

@@ -0,0 +1,32 @@
1
+#!/bin/bash
2
+#
3
+# Copyright (C) 2010 Stefan Hajnoczi <stefanha@gmail.com>.
4
+#
5
+# This program is free software; you can redistribute it and/or
6
+# modify it under the terms of the GNU General Public License as
7
+# published by the Free Software Foundation; either version 2 of the
8
+# License, or any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful, but
11
+# WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+# General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program; if not, write to the Free Software
17
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
+
19
+if [ $# != 2 ]
20
+then
21
+	cat >&2 <<EOF
22
+usage: $0 <elf-binary> <addresses-file>
23
+Look up symbol names in <elf-binary> for function addresses from
24
+<addresses-file>.
25
+
26
+Example:
27
+$0 bin/gpxe.hd.tmp fnrec.dat
28
+EOF
29
+	exit 1
30
+fi
31
+
32
+tr ' ' '\n' <"$2" | addr2line -fe "$1" | awk '(NR % 2) { print }'

Loading…
Annulla
Salva