Skip to contentSkip to conversation

mips-specific ftrace support

PATCH Superseded [email protected] 3 participants 17 messages May 29, 2009 – Jun 4, 2009

Subsystems (5)
Kbuild MIPS Tracing ptrace support +1 more subsystems

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover mips-specific ftrace support

From: Wu Zhangjin <[email protected]>

ftrace is a mcount based kernel tracing tool/framework, which is originally from RT_PREEMPT(http://rt.wiki.kernel.org).

ftrace is short for function tracer, this is its original name, but now, it becomes a kernel tracing framework, lots of kernel tracers are built on it, such as irqoff tracer, wakeup tracer and so forth. these tracers are arch-independent(?), but some of them are arch-dependent, such as the original
ftrace: function tracer, and dynamic function tracer, function graph tracer, and also, system call tracer.

here is the mips porting of these four arch-dependent tracers, it will enable the following new kernel config options in linux-mips system.

kernel hacking --->
Tracers -->
[*] Kernel Function Tracer
[*] Kernel Function Graph Tracer
...
[*] Trace syscalls
...
[*] enable/disable ftrace tracepoints dynamically

in reality, because the timestamp getting function are arch-dependent, lots of the tracers are arch-dependent. the arch-dependent part is that: sched_clock. the original sched_clock in mips is jiffes based, only give 10ms precision in 1000HZ, which is not enough for ftrace. to get high-precise timestamp, we must implement a new native_sched_clock via reading the MIPS clock counter, but since it is only 32bit long, so, overflow should be handled carefully.

this -v2 patch series is based on the -v1 patch series and incorporates the feedback from Steven Rostedt and Thomas Gleixner.

read the following document, and play with it:
Documentation/trace/ftrace.txt

Wu Zhangjin (6):
mips static function tracer support
mips dynamic function tracer support
add an endian argument to scripts/recordmcount.pl mips function graph tracer support
mips specific clock function to get precise timestamp mips specific system call tracer

 arch/mips/Kconfig                   |    7 +
 arch/mips/Makefile                  |    2 +
 arch/mips/include/asm/ftrace.h      |   35 ++++-
 arch/mips/include/asm/ptrace.h      |    2 +
 arch/mips/include/asm/reg.h         |    5 +
 arch/mips/include/asm/syscall.h     |   84 +++++++++
 arch/mips/include/asm/thread_info.h |    5 +-
 arch/mips/kernel/Makefile           |   12 ++
 arch/mips/kernel/csrc-r4k.c         |    2 +-
 arch/mips/kernel/entry.S            |    2 +-
 arch/mips/kernel/ftrace.c           |  350 +++++++++++++++++++++++++++++++++++
 arch/mips/kernel/ftrace_clock.c     |   71 +++++++
 arch/mips/kernel/mcount.S           |  185 ++++++++++++++++++
 arch/mips/kernel/mips_ksyms.c       |    5 +
 arch/mips/kernel/ptrace.c           |   14 ++-
 arch/mips/kernel/scall64-o32.S      |    2 +-
 arch/mips/kernel/vmlinux.lds.S      |    1 +
 kernel/trace/trace_clock.c          |    2 +-
 scripts/Makefile.build              |    1 +
 scripts/recordmcount.pl             |   32 +++-
 20 files changed, 805 insertions(+), 14 deletions(-)
 create mode 100644 arch/mips/include/asm/syscall.h
 create mode 100644 arch/mips/kernel/ftrace.c
 create mode 100644 arch/mips/kernel/ftrace_clock.c
 create mode 100644 arch/mips/kernel/mcount.S
#1 lore raw

PATCH v2 1/6 mips static function tracer support

From: Wu Zhangjin <[email protected]>

if -pg of gcc is enabled. a calling to _mcount will be inserted to each kernel function. so, there is a possibility to trace the functions in _mcount.

here is the implementation of mips specific _mcount for static function tracer.

-ffunction-sections option not works with -pg, so disable it if enables FUNCTION_TRACER.

---
 arch/mips/Kconfig              |    2 +
 arch/mips/Makefile             |    2 +
 arch/mips/include/asm/ftrace.h |   25 ++++++++++-
 arch/mips/kernel/Makefile      |    7 +++
 arch/mips/kernel/mcount.S      |   98 ++++++++++++++++++++++++++++++++++++++++
 arch/mips/kernel/mips_ksyms.c  |    5 ++
 6 files changed, 138 insertions(+), 1 deletions(-)
 create mode 100644 arch/mips/kernel/mcount.S
arch/mips/Kconfig +2 -0
index 09b1287..d5c01ca 100644
@@ -4,6 +4,8 @@ config MIPS
 	select HAVE_IDE
 	select HAVE_OPROFILE
 	select HAVE_ARCH_KGDB
+	select HAVE_FUNCTION_TRACER
+	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	# Horrible source of confusion.  Die, die, die ...
 	select EMBEDDED
 	select RTC_LIB
arch/mips/Makefile +2 -0
index c4cae9e..f86fb15 100644
@@ -48,7 +48,9 @@ ifneq ($(SUBARCH),$(ARCH))
   endif
 endif
 
+ifndef CONFIG_FUNCTION_TRACER
 cflags-y := -ffunction-sections
+endif
 cflags-y += $(call cc-option, -mno-check-zero-division)
 
 ifdef CONFIG_32BIT
arch/mips/include/asm/ftrace.h +24 -1
index 40a8c17..5f8ebcf 100644
@@ -1 +1,24 @@
-/* empty */
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Author: Wu Zhangjin <[email protected]>
+ */
+
+#ifndef _ASM_MIPS_FTRACE_H
+#define _ASM_MIPS_FTRACE_H
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_ADDR ((unsigned long)(_mcount))
+#define MCOUNT_INSN_SIZE 4		/* sizeof mcount call */
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+#define mcount _mcount
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_TRACER */
+#endif /* _ASM_MIPS_FTRACE_H */
arch/mips/kernel/Makefile +7 -0
index e961221..559a820 100644
@@ -8,6 +8,11 @@ obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 		   ptrace.o reset.o setup.o signal.o syscall.o \
 		   time.o topology.o traps.o unaligned.o watch.o
 
+ifdef CONFIG_FUNCTION_TRACER
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_early_printk.o = -pg
+endif
+
 obj-$(CONFIG_CEVT_BCM1480)	+= cevt-bcm1480.o
 obj-$(CONFIG_CEVT_R4K_LIB)	+= cevt-r4k.o
 obj-$(CONFIG_MIPS_MT_SMTC)	+= cevt-smtc.o
@@ -24,6 +29,8 @@ obj-$(CONFIG_SYNC_R4K)		+= sync-r4k.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
+obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
+
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_MIPS32)	+= r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_MIPS64)	+= r4k_fpu.o r4k_switch.o
arch/mips/kernel/mcount.S new file +98 -0

98 lines not on this page · raw message

arch/mips/kernel/mips_ksyms.c +5 -0
index 225755d..1d04807 100644
@@ -13,6 +13,7 @@
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
+#include <asm/ftrace.h>
 
 extern void *__bzero(void *__s, size_t __count);
 extern long __strncpy_from_user_nocheck_asm(char *__to,
@@ -51,3 +52,7 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck);
 EXPORT_SYMBOL(__csum_partial_copy_user);
 
 EXPORT_SYMBOL(invalid_pte_table);
+#ifdef CONFIG_FUNCTION_TRACER
+/* _mcount is defined in arch/mips/kernel/mcount.S */
+EXPORT_SYMBOL(_mcount);
+#endif
Signature · 1 line
1.6.0.4
#2 lore raw

PATCH v2 2/6 mips dynamic function tracer support

In reply to [email protected]

From: Wu Zhangjin <[email protected]>

dynamic function tracer need to replace "nop" to "jumps & links" and something reversely.

---
 arch/mips/Kconfig              |    3 +
 arch/mips/include/asm/ftrace.h |   10 ++
 arch/mips/kernel/Makefile      |    2 +
 arch/mips/kernel/ftrace.c      |  207 ++++++++++++++++++++++++++++++++++++++++
 arch/mips/kernel/mcount.S      |   31 ++++++
 scripts/recordmcount.pl        |   17 +++-
 6 files changed, 267 insertions(+), 3 deletions(-)
 create mode 100644 arch/mips/kernel/ftrace.c
arch/mips/Kconfig +3 -0
index d5c01ca..0c00536 100644
@@ -6,6 +6,9 @@ config MIPS
 	select HAVE_ARCH_KGDB
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	select HAVE_DYNAMIC_FTRACE
+	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
 	# Horrible source of confusion.  Die, die, die ...
 	select EMBEDDED
 	select RTC_LIB
arch/mips/include/asm/ftrace.h +10 -0
index 5f8ebcf..b4970c9 100644
@@ -19,6 +19,16 @@
 extern void _mcount(void);
 #define mcount _mcount
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /*  CONFIG_DYNAMIC_FTRACE */
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 #endif /* _ASM_MIPS_FTRACE_H */
arch/mips/kernel/Makefile +2 -0
index 559a820..8dabcc6 100644
@@ -10,6 +10,7 @@ obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
@@ -30,6 +31,7 @@ obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
+obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o
 
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_MIPS32)	+= r4k_fpu.o r4k_switch.o
arch/mips/kernel/ftrace.c new file +207 -0

207 lines not on this page · raw message

arch/mips/kernel/mcount.S +31 -0
index 268724e..ce8a0ba 100644
@@ -67,6 +67,35 @@
 	move ra, $1
 	.endm
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+LEAF(_mcount)
+	RESTORE_SP_FOR_32BIT
+ 	RETURN_BACK
+ 	END(_mcount)
+
+NESTED(ftrace_caller, PT_SIZE, ra)
+	RESTORE_SP_FOR_32BIT
+	lw	t0, function_trace_stop
+	bnez	t0, ftrace_stub
+	nop
+
+	MCOUNT_SAVE_REGS
+
+	MCOUNT_SET_ARGS
+	.globl ftrace_call
+ftrace_call:
+	jal	ftrace_stub
+	nop
+
+	MCOUNT_RESTORE_REGS
+	.globl ftrace_stub
+ftrace_stub:
+	RETURN_BACK
+	END(ftrace_caller)
+
+#else	/* ! CONFIG_DYNAMIC_FTRACE */
+
 NESTED(_mcount, PT_SIZE, ra)
 	RESTORE_SP_FOR_32BIT
 	PTR_L	t0, function_trace_stop
@@ -94,5 +123,7 @@ ftrace_stub:
 	RETURN_BACK
 	END(_mcount)
 
+#endif	/* ! CONFIG_DYNAMIC_FTRACE */
+
 	.set at
 	.set reorder
scripts/recordmcount.pl +14 -3
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;
 
     #
     # Step 7: Convert the local functions back into local symbols
@@ -454,7 +465,7 @@ if ($#converts >= 0) {
     `$objcopy $locallist $globalmix $inputfile`;
 
     # Remove the temp files
-    `$rm $globalobj $globalmix`;
+    `$rm $globalobj $globalmix 2>&1 >/dev/null`;
 
 } else {
 
Signature · 1 line
1.6.0.4
maintainer
#3 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

Quoted 24 lines · On Fri, 29 May 2009, [email protected] wrote:
scripts/recordmcount.pl +11 -0
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #

scripts/recordmcount.pl if ($#converts >= 0) { · line 460

Quoted 10 lines
scripts/recordmcount.pl +2 -2
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;

We still need to find out why these are giving errors. I don't like the idea of hiding errors that might be useful. The better way is to change the code to avoid having any warnings or errors.

-- Steve

Quoted 16 lines
scripts/recordmcount.pl +1 -1
     #
     # Step 7: Convert the local functions back into local symbols
@@ -454,7 +465,7 @@ if ($#converts >= 0) {
     `$objcopy $locallist $globalmix $inputfile`;
 
     # Remove the temp files
-    `$rm $globalobj $globalmix`;
+    `$rm $globalobj $globalmix 2>&1 >/dev/null`;
 
 } else {
 
Signature · 1 line
1.6.0.4
#4 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

Quoted 30 lines · Steven Rostedt
Quoted 29 lines · On Fri, 29 May 2009, [email protected] wrote:
scripts/recordmcount.pl +12 -1
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
Quoted 9 lines

scripts/recordmcount.pl if ($#converts >= 0) { · line 460

Quoted 5 lines
scripts/recordmcount.pl +1 -1
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;

We still need to find out why these are giving errors. I don't like the idea of hiding errors that might be useful. The better way is to change the code to avoid having any warnings or errors.

get it :-)
I'm tuning it currently.

thanks!
Wu Zhangjin

Quoted 20 lines

-- Steve

Quoted 16 lines
scripts/recordmcount.pl +1 -1
     #
     # Step 7: Convert the local functions back into local symbols
@@ -454,7 +465,7 @@ if ($#converts >= 0) {
     `$objcopy $locallist $globalmix $inputfile`;
 
     # Remove the temp files
-    `$rm $globalobj $globalmix`;
+    `$rm $globalobj $globalmix 2>&1 >/dev/null`;
 
 } else {
 
Signature · 1 line
1.6.0.4
#5 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

In reply to Steven Rostedt
Quoted 30 lines · Steven Rostedt
Quoted 29 lines · On Fri, 29 May 2009, [email protected] wrote:
scripts/recordmcount.pl +12 -1
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
Quoted 10 lines

scripts/recordmcount.pl if ($#converts >= 0) { · line 460

Quoted 5 lines
scripts/recordmcount.pl +1 -1
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;

We still need to find out why these are giving errors. I don't like the idea of hiding errors that might be useful. The better way is to change the code to avoid having any warnings or errors.

ooh, there is really a bug in scripts/recordmcount.pl, just fixed it.

warnings like this(only in mips/64bit):

CC fs/proc/devices.o
mipsel-linux-gnu-objcopy: 'fs/proc/.tmp_gl_devices.o': No such file
mipsel-linux-gnu-ld: fs/proc/.tmp_gl_devices.o: No such file: No such file or directory
rm: cannot remove `fs/proc/.tmp_gl_devices.o': No such file or directory
rm: cannot remove `fs/proc/.tmp_mx_devices.o': No such file or directory

so i checked the source code and let it print something:

     #
     # Step 5: set up each local function as a global
     #
+    print "$objcopy $globallist $inputfile $globalobj\n";
     `$objcopy $globallist $inputfile $globalobj`;

something like this is printed:

mipsel-linux-gnu-objcopy --globalize-symbol $L12 arch/mips/kernel/irq_cpu.o arch/mips/kernel/.tmp_gl_irq_cpu.o
mipsel-linux-gnu-objcopy: 'arch/mips/kernel/.tmp_gl_irq_cpu.o': No such file
mipsel-linux-gnu-ld: arch/mips/kernel/.tmp_gl_irq_cpu.o: No such file:
No such file or directory
rm: cannot remove `arch/mips/kernel/.tmp_gl_irq_cpu.o': No such file or directory
rm: cannot remove `arch/mips/kernel/.tmp_mx_irq_cpu.o': No such file or directory

did you see the symbol: $L12, which should be quoted, otherwise, it will be interpreted as the value of a variable L12(the whole $L12 should be a string), this $L12 will be an empty string. so, the whole command becomes:

mipsel-linux-gnu-objcopy --globalize-symbol arch/mips/kernel/irq_cpu.o arch/mips/kernel/.tmp_gl_irq_cpu.o

the last string .../.tmp_gl_irq_cpu.o becomes the input file, but it's not there, that is the warning.

fix it like this:

scripts/recordmcount.pl +2 -2
index 59ea43a..907110e 100755
@@ -451,8 +451,8 @@ if ($#converts >= 0) {
     my $locallist = "";
 
     foreach my $con (@converts) {
-       $globallist .= " --globalize-symbol $con";
-       $locallist .= " --localize-symbol $con";
+       $globallist .= " --globalize-symbol \"$con\"";
+       $locallist .= " --localize-symbol \"$con\"";
     }
 
     my $globalobj = $dirname . "/.tmp_gl_" . $filename;

I will add this as the third patch, is it okay?

Best Wishes,
--- Wu Zhangjin

#6 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

Quoted 104 lines · Wu Zhangjin
Quoted 30 lines · Steven Rostedt
Quoted 29 lines · On Fri, 29 May 2009, [email protected] wrote:
scripts/recordmcount.pl +12 -1
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
Quoted 10 lines

scripts/recordmcount.pl if ($#converts >= 0) { · line 460

Quoted 5 lines
scripts/recordmcount.pl +1 -1
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;

We still need to find out why these are giving errors. I don't like the idea of hiding errors that might be useful. The better way is to change the code to avoid having any warnings or errors.

ooh, there is really a bug in scripts/recordmcount.pl, just fixed it.

warnings like this(only in mips/64bit):

CC fs/proc/devices.o
mipsel-linux-gnu-objcopy: 'fs/proc/.tmp_gl_devices.o': No such file
mipsel-linux-gnu-ld: fs/proc/.tmp_gl_devices.o: No such file: No such file or directory
rm: cannot remove `fs/proc/.tmp_gl_devices.o': No such file or directory
rm: cannot remove `fs/proc/.tmp_mx_devices.o': No such file or directory

so i checked the source code and let it print something:

     #
     # Step 5: set up each local function as a global
     #
+    print "$objcopy $globallist $inputfile $globalobj\n";
     `$objcopy $globallist $inputfile $globalobj`;

something like this is printed:

mipsel-linux-gnu-objcopy --globalize-symbol $L12 arch/mips/kernel/irq_cpu.o arch/mips/kernel/.tmp_gl_irq_cpu.o
mipsel-linux-gnu-objcopy: 'arch/mips/kernel/.tmp_gl_irq_cpu.o': No such file
mipsel-linux-gnu-ld: arch/mips/kernel/.tmp_gl_irq_cpu.o: No such file:
No such file or directory
rm: cannot remove `arch/mips/kernel/.tmp_gl_irq_cpu.o': No such file or directory
rm: cannot remove `arch/mips/kernel/.tmp_mx_irq_cpu.o': No such file or directory

did you see the symbol: $L12, which should be quoted, otherwise, it will be interpreted as the value of a variable L12(the whole $L12 should be a string), this $L12 will be an empty string. so, the whole command becomes:

mipsel-linux-gnu-objcopy --globalize-symbol arch/mips/kernel/irq_cpu.o arch/mips/kernel/.tmp_gl_irq_cpu.o

the last string .../.tmp_gl_irq_cpu.o becomes the input file, but it's not there, that is the warning.

fix it like this:

scripts/recordmcount.pl +2 -2
index 59ea43a..907110e 100755
@@ -451,8 +451,8 @@ if ($#converts >= 0) {
     my $locallist = "";
 
     foreach my $con (@converts) {
-       $globallist .= " --globalize-symbol $con";
-       $locallist .= " --localize-symbol $con";
+       $globallist .= " --globalize-symbol \"$con\"";
+       $locallist .= " --localize-symbol \"$con\"";
     }
 
     my $globalobj = $dirname . "/.tmp_gl_" . $filename;
Quoted 2 lines

I will add this as the third patch, is it okay?

sorry, this fix not work, can not link the kernel:

arch/mips/kernel/built-in.o:(__mcount_loc+0x3a0): undefined reference to `$L12'
arch/mips/kernel/built-in.o:(__mcount_loc+0x3a8): undefined reference to `$L12'

I think we should ignore these symbols, should we?

Quoted 2 lines

Best Wishes,
--- Wu Zhangjin

#7 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

In reply to [email protected]

hi Wu,

I have one question about dynamic ftrace support for modules on mips arch.
I have also ported a dynamic ftrace of mips before, but when I using modules with dynamic ftrace enabled in mips, I have following error:

# insmod ./usbcore
module usbcore: relocation overflow
insmod: cannot insert './usbcore.ko': invalid module format
#

I have no time to test your patch, but I think your patch also has this problem.

Below I explain possibility of this problem in details:

We know that on mips, kernel symbol will locate in 0x80000000~0x90000000, and modules' symbol will locate in >0xc0000000.

On mips, gcc will insert following assembler code before every functions:

move at,ra
jal 0 <usb_ifnum_to_if>
10: R_MIPS_26 _mcount

Here "_mcount" is a kernel symbol in 0x80000000~0x90000000, for example at 0x8027a740.

When loading a module, kernel should relocate "jal 0" instruction to jump to the kernel's "_mcount" address, 0x8027a740. But "jal 0" is a 26 bits offset jump instruction, it only can be relocated to jump to modules' symbol address
space(>0xc0000000) and it can't be relocated to jump to kernel symbol address
space(such as 0x8027a740), because offset is 32 bits(is 0xc0000000 -
0x80000000). We can't modify this instruction to jump to a 32 offset address
except that we modify gcc compiler to insert other assembler codes.

So, when installing modules, the kernel will try to relocate "jal 0" instruction
to instruction of jumping to >0xc0000000, but it finds that _mcount's address
is 0x8027a740 and then print error indicated that it can't be reloacted.

The following source code is the checking place:

----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)

{
    ...
    if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
                printk(KERN_ERR
                       "module %s: relocation overflow, v:%x, location:%x\n",
                       me->name, v, (unsigned long)location);
                return -ENOEXEC;
        }

    *location = (*location & ~0x03ffffff) |
                    ((*location + (v >> 2)) & 0x03ffffff);

} ----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

v is kernel _mcount's address, location is the address of the instrution that should be relocated;

To resolve this problem, we may need to do more work, either on gcc or on the kernel. So I want to hear your test result and if you have solution, please let me know.

Thanks a lot!

Liming Wang

Quoted 379 lines · [email protected] wrote:

From: Wu Zhangjin <[email protected]>

dynamic function tracer need to replace "nop" to "jumps & links" and something reversely.

---
 arch/mips/Kconfig              |    3 +
 arch/mips/include/asm/ftrace.h |   10 ++
 arch/mips/kernel/Makefile      |    2 +
 arch/mips/kernel/ftrace.c      |  207 ++++++++++++++++++++++++++++++++++++++++
 arch/mips/kernel/mcount.S      |   31 ++++++
 scripts/recordmcount.pl        |   17 +++-
 6 files changed, 267 insertions(+), 3 deletions(-)
 create mode 100644 arch/mips/kernel/ftrace.c
arch/mips/Kconfig +3 -0
index d5c01ca..0c00536 100644
@@ -6,6 +6,9 @@ config MIPS
 	select HAVE_ARCH_KGDB
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	select HAVE_DYNAMIC_FTRACE
+	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
 	# Horrible source of confusion.  Die, die, die ...
 	select EMBEDDED
 	select RTC_LIB
arch/mips/include/asm/ftrace.h +10 -0
index 5f8ebcf..b4970c9 100644
@@ -19,6 +19,16 @@
 extern void _mcount(void);
 #define mcount _mcount
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /*  CONFIG_DYNAMIC_FTRACE */
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 #endif /* _ASM_MIPS_FTRACE_H */
arch/mips/kernel/Makefile +2 -0
index 559a820..8dabcc6 100644
@@ -10,6 +10,7 @@ obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
@@ -30,6 +31,7 @@ obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
+obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o
 
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_MIPS32)	+= r4k_fpu.o r4k_switch.o
arch/mips/kernel/ftrace.c new file +207 -0
new file mode 100644
index 0000000..ad490cc
@@ -0,0 +1,207 @@
+/*
+ * Code for replacing ftrace calls with jumps.
+ *
+ * Copyright (C) 2007-2008 Steven Rostedt <[email protected]>
+ * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Author: Wu Zhangjin <[email protected]>
+ *
+ * Thanks goes to Steven Rostedt for writing the original x86 version.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/hardirq.h>
+#include <linux/uaccess.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/ftrace.h>
+
+#include <asm/cacheflush.h>
+#include <asm/ftrace.h>
+#include <asm/asm.h>
+#include <asm/unistd.h>
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+#define JAL 0x0c000000	/* jump & link: ip --> ra, jump to target */
+#define ADDR_MASK 0x03ffffff	/*  op_code|addr : 31...26|25 ....0 */
+
+static unsigned int ftrace_nop = 0x00000000;
+
+static unsigned char *ftrace_call_replace(unsigned long op_code,
+					  unsigned long addr)
+{
+    static unsigned int op;
+
+    op = op_code | ((addr >> 2) & ADDR_MASK);
+
+    return (unsigned char *) &op;
+}
+
+static atomic_t nmi_running = ATOMIC_INIT(0);
+static int mod_code_status;	/* holds return value of text write */
+static int mod_code_write;	/* set when NMI should do the write */
+static void *mod_code_ip;	/* holds the IP to write to */
+static void *mod_code_newcode;	/* holds the text to write to the IP */
+
+static unsigned nmi_wait_count;
+static atomic_t nmi_update_count = ATOMIC_INIT(0);
+
+int ftrace_arch_read_dyn_info(char *buf, int size)
+{
+    int r;
+
+    r = snprintf(buf, size, "%u %u",
+		 nmi_wait_count, atomic_read(&nmi_update_count));
+    return r;
+}
+
+static void ftrace_mod_code(void)
+{
+    /*
+     * Yes, more than one CPU process can be writing to mod_code_status.
+     *    (and the code itself)
+     * But if one were to fail, then they all should, and if one were
+     * to succeed, then they all should.
+     */
+    mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
+					 MCOUNT_INSN_SIZE);
+
+    /* if we fail, then kill any new writers */
+    if (mod_code_status)
+		mod_code_write = 0;
+}
+
+void ftrace_nmi_enter(void)
+{
+    atomic_inc(&nmi_running);
+    /* Must have nmi_running seen before reading write flag */
+    smp_mb();
+    if (mod_code_write) {
+		ftrace_mod_code();
+		atomic_inc(&nmi_update_count);
+    }
+}
+
+void ftrace_nmi_exit(void)
+{
+    /* Finish all executions before clearing nmi_running */
+    smp_wmb();
+    atomic_dec(&nmi_running);
+}
+
+static void wait_for_nmi(void)
+{
+    int waited = 0;
+
+    while (atomic_read(&nmi_running)) {
+		waited = 1;
+		cpu_relax();
+    }
+
+    if (waited)
+		nmi_wait_count++;
+}
+
+static int do_ftrace_mod_code(unsigned long ip, void *new_code)
+{
+    mod_code_ip = (void *) ip;
+    mod_code_newcode = new_code;
+
+    /* The buffers need to be visible before we let NMIs write them */
+    smp_wmb();
+
+    mod_code_write = 1;
+
+    /* Make sure write bit is visible before we wait on NMIs */
+    smp_mb();
+
+    wait_for_nmi();
+
+    /* Make sure all running NMIs have finished before we write the code */
+    smp_mb();
+
+    ftrace_mod_code();
+
+    /* Make sure the write happens before clearing the bit */
+    smp_wmb();
+
+    mod_code_write = 0;
+
+    /* make sure NMIs see the cleared bit */
+    smp_mb();
+
+    wait_for_nmi();
+
+    return mod_code_status;
+}
+
+static unsigned char *ftrace_nop_replace(void)
+{
+    return (unsigned char *) &ftrace_nop;
+}
+
+static int
+ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+		   unsigned char *new_code)
+{
+    unsigned char replaced[MCOUNT_INSN_SIZE];
+
+    /* read the text we want to modify */
+    if (probe_kernel_read(replaced, (void *) ip, MCOUNT_INSN_SIZE))
+		return -EFAULT;
+
+    /* Make sure it is what we expect it to be */
+    if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
+		return -EINVAL;
+
+    /* replace the text with the new text */
+    if (do_ftrace_mod_code(ip, new_code))
+		return -EPERM;
+
+    return 0;
+}
+
+int ftrace_make_nop(struct module *mod,
+		    struct dyn_ftrace *rec, unsigned long addr)
+{
+    unsigned char *new, *old;
+
+    old = ftrace_call_replace(JAL, addr);
+    new = ftrace_nop_replace();
+
+    return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+    unsigned char *new, *old;
+
+    old = ftrace_nop_replace();
+    new = ftrace_call_replace(JAL, addr);
+
+    return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+    unsigned long ip = (unsigned long) (&ftrace_call);
+    unsigned char old[MCOUNT_INSN_SIZE], *new;
+    int ret;
+
+    memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
+    new = ftrace_call_replace(JAL, (unsigned long) func);
+    ret = ftrace_modify_code(ip, old, new);
+
+    return ret;
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+    /* The return code is retured via data */
+    *(unsigned long *) data = 0;
+
+    return 0;
+}
+#endif				/* CONFIG_DYNAMIC_FTRACE */
arch/mips/kernel/mcount.S +31 -0
index 268724e..ce8a0ba 100644
@@ -67,6 +67,35 @@
 	move ra, $1
 	.endm
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+LEAF(_mcount)
+	RESTORE_SP_FOR_32BIT
+ 	RETURN_BACK
+ 	END(_mcount)
+
+NESTED(ftrace_caller, PT_SIZE, ra)
+	RESTORE_SP_FOR_32BIT
+	lw	t0, function_trace_stop
+	bnez	t0, ftrace_stub
+	nop
+
+	MCOUNT_SAVE_REGS
+
+	MCOUNT_SET_ARGS
+	.globl ftrace_call
+ftrace_call:
+	jal	ftrace_stub
+	nop
+
+	MCOUNT_RESTORE_REGS
+	.globl ftrace_stub
+ftrace_stub:
+	RETURN_BACK
+	END(ftrace_caller)
+
+#else	/* ! CONFIG_DYNAMIC_FTRACE */
+
 NESTED(_mcount, PT_SIZE, ra)
 	RESTORE_SP_FOR_32BIT
 	PTR_L	t0, function_trace_stop
@@ -94,5 +123,7 @@ ftrace_stub:
 	RETURN_BACK
 	END(_mcount)
 
+#endif	/* ! CONFIG_DYNAMIC_FTRACE */
+
 	.set at
 	.set reorder
scripts/recordmcount.pl +14 -3
index 409596e..a5d2ace 100755
@@ -213,6 +213,17 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+
+} elsif ($arch eq "mips") {
+	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+	$ld .= " -melf".$bits."btsmip";
+
+	$cc .= " -mno-abicalls -fno-pic ";
+
+    if ($bits == 64) {
+		$type = ".dword";
+    }
+
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
@@ -441,12 +452,12 @@ if ($#converts >= 0) {
     #
     # Step 5: set up each local function as a global
     #
-    `$objcopy $globallist $inputfile $globalobj`;
+    `$objcopy $globallist $inputfile $globalobj 2>&1 >/dev/null`;
 
     #
     # Step 6: Link the global version to our list.
     #
-    `$ld -r $globalobj $mcount_o -o $globalmix`;
+    `$ld -r $globalobj $mcount_o -o $globalmix 2>&1 >/dev/null`;
 
     #
     # Step 7: Convert the local functions back into local symbols
@@ -454,7 +465,7 @@ if ($#converts >= 0) {
     `$objcopy $locallist $globalmix $inputfile`;
 
     # Remove the temp files
-    `$rm $globalobj $globalmix`;
+    `$rm $globalobj $globalmix 2>&1 >/dev/null`;
 
 } else {
 
#8 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

hi,

sorry, I'm so late to reply your E-mail, a little busy these days.

Quoted 66 lines · Wang Liming

hi Wu,

I have one question about dynamic ftrace support for modules on mips arch. I have also ported a dynamic ftrace of mips before, but when I using modules with dynamic ftrace enabled in mips, I have following error:

# insmod ./usbcore
module usbcore: relocation overflow
insmod: cannot insert './usbcore.ko': invalid module format
#

I have no time to test your patch, but I think your patch also has this problem.

Below I explain possibility of this problem in details:

We know that on mips, kernel symbol will locate in 0x80000000~0x90000000, and modules' symbol will locate in >0xc0000000.

On mips, gcc will insert following assembler code before every functions:

move at,ra
jal 0 <usb_ifnum_to_if>
10: R_MIPS_26 _mcount

Here "_mcount" is a kernel symbol in 0x80000000~0x90000000, for example at 0x8027a740.

When loading a module, kernel should relocate "jal 0" instruction to jump to the kernel's "_mcount" address, 0x8027a740. But "jal 0" is a 26 bits offset jump
instruction, it only can be relocated to jump to modules' symbol address space(>0xc0000000) and it can't be relocated to jump to kernel symbol address
space(such as 0x8027a740), because offset is 32 bits(is 0xc0000000 - 0x80000000). We can't modify this instruction to jump to a 32 offset address except that we modify gcc compiler to insert other assembler codes.

So, when installing modules, the kernel will try to relocate "jal 0" instruction
to instruction of jumping to >0xc0000000, but it finds that _mcount's
address
is 0x8027a740 and then print error indicated that it can't be reloacted.

The following source code is the checking place:

----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)

{
   ...
   if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
               printk(KERN_ERR
                      "module %s: relocation overflow, v:%x, location:%x\n",
                      me->name, v, (unsigned long)location);
               return -ENOEXEC;
       }

   *location = (*location & ~0x03ffffff) |
                   ((*location + (v >> 2)) & 0x03ffffff);

} ----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

Quoted 7 lines

v is kernel _mcount's address, location is the address of the instrution that should be relocated;

To resolve this problem, we may need to do more work, either on gcc or on the kernel. So I want to hear your test result and if you have solution, please let me know.

yes, current version of mips-specific dynamic ftrace not support modules yet.

there is similar solution implemented in PowerPC(something named trampoline), although I did not look into it, but I'm sure we can implement the mips-specific one
via imitating it.

and currently, I'm planning to fix it in the -v3 of mips-specific ftrace support.

best wishes,
Wu Zhangjin

#9 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

Quoted 15 lines · wu zhangjin

hi,

sorry, I'm so late to reply your E-mail, a little busy these days.

Quoted 11 lines

} ----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

v is kernel _mcount's address, location is the address of the instrution that should be relocated;

To resolve this problem, we may need to do more work, either on gcc or on the kernel. So I want to hear your test result and if you have solution, please let me know.

Quoted 6 lines

yes, current version of mips-specific dynamic ftrace not support modules yet.

there is similar solution implemented in PowerPC(something named trampoline), although I did not look into it, but I'm sure we can implement the mips-specific one
via imitating it.

Good hit. I may have a look on Powerpc implementation.

Quoted 3 lines

and currently, I'm planning to fix it in the -v3 of mips-specific ftrace support.

OK. I'm looking forward to your -v3 patches.

Thanks.
Liming Wang

Quoted 4 lines

best wishes,
Wu Zhangjin

maintainer
#10 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

Quoted 20 lines · Wang Liming
Quoted 19 lines · wu zhangjin

hi,

sorry, I'm so late to reply your E-mail, a little busy these days.

Quoted 12 lines

}

----------arch/mips/kernel/module.c:apply_r_mips_26_rel()-------------------

v is kernel _mcount's address, location is the address of the instrution that should be relocated;

To resolve this problem, we may need to do more work, either on gcc or on the kernel. So I want to hear your test result and if you have solution, please let me know.

yes, current version of mips-specific dynamic ftrace not support modules yet.

Quoted 6 lines
Quoted 5 lines

there is similar solution implemented in PowerPC(something named trampoline),
although I did not look into it, but I'm sure we can implement the mips-specific one
via imitating it.

Good hit. I may have a look on Powerpc implementation.

Note, PowerPC uses a trampoline from modules to kernel core. I think MIPS just calls mcount differently. That is, it does a full 32bit address call (64 bit for 64 bit archs?). Something like:

	lui	v1, _mcount
	addiu	v1, v1, _mcount
	jalr	v1
	addiu	sp, sp, -8

Then a nop would not do. Due to preemption, we can not modify more than one line. But you could modify it to:

	b	1f
	addiu	v1, v1, _mcount
	jalr	v1
	addiu	sp, sp, -8

1:

Clobbering v1 should not be an issue since it is already used to store _mcount. That is, we still do the addiu v1,v1,_mcount with that branch. But v1 should be ignored.

-- Steve

#11 lore raw

Re: [PATCH v2 2/6] mips dynamic function tracer support

hi, Steven

Quoted 16 lines

Note, PowerPC uses a trampoline from modules to kernel core. I think MIPS just calls mcount differently. That is, it does a full 32bit address call (64 bit for 64 bit archs?). Something like:

	lui	v1, _mcount
	addiu	v1, v1, _mcount
	jalr	v1
	addiu	sp, sp, -8

Then a nop would not do. Due to preemption, we can not modify more than one line. But you could modify it to:

	b	1f
	addiu	v1, v1, _mcount
	jalr	v1
	addiu	sp, sp, -8
Quoted 6 lines

1:

Clobbering v1 should not be an issue since it is already used to store _mcount. That is, we still do the addiu v1,v1,_mcount with that branch. But v1 should be ignored.

sorry, I'm not clear what you said above, could you give more explanation on it, thanks!

I think "jal _mcount" itself will not work in static and dynamic ftrace. something like what you described above should be used instead. perhaps a PATCH can be sent to gcc or we use some tricks in kernel.

if we not use the method of modifying the kernel code in run time(avoid preemption?), can we link something as following to the modules:

_mcount_trampoline:

	PTR_LA	t0, _mcount
	jalr	t0

and then we replace the original "jal _mcount" in every module to "jal _mcount_trampoline" with a perl script.

this solution maybe work for static ftrace. does it?

but in dynamic ftrace, when ftrace is enabled and set_filter_function is set, the place of filtered function will be substituted to "jal ftrace_caller", this will not work since ftrace_caller is a function like _mcount, which will not reached in modules. so, this ftrace_caller should be substituted to something like this:

ftrace_caller_trampoline:

	PTR_LA	t0, ftrace_caller
	jalr	t0

and ftrace_caller_trampoline should be linked to modules too. or we substituted it to the above _mcount_trampoline, but change "PTR_LA t0, _mcount" to "PTR_LA t0, ftrace_caller".

does this work?

thanks!
Wu Zhangjin

#12 lore raw

PATCH v2 3/6 add an endian argument to scripts/recordmcount.pl

In reply to [email protected]

From: Wu Zhangjin <[email protected]>

mips architecture need this argument to handle big/little endian differently.

---
 scripts/Makefile.build  |    1 +
 scripts/recordmcount.pl |   21 +++++++++++++++------
 2 files changed, 16 insertions(+), 6 deletions(-)
scripts/Makefile.build +1 -0
index 5c4b7a4..548d575 100644
@@ -207,6 +207,7 @@ endif
 
 ifdef CONFIG_FTRACE_MCOUNT_RECORD
 cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
+	"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
 	"$(if $(CONFIG_64BIT),64,32)" \
 	"$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
 	"$(if $(part-of-module),1,0)" "$(@)";
scripts/recordmcount.pl +14 -5
index a5d2ace..57a2b6a 100755
@@ -100,13 +100,13 @@ $P =~ s@.*/@@g;
 
 my $V = '0.1';
 
-if ($#ARGV < 7) {
-	print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n";
+if ($#ARGV < 8) {
+	print "usage: $P arch endian bits objdump objcopy cc ld nm rm mv is_module inputfile\n";
 	print "version: $V\n";
 	exit(1);
 }
 
-my ($arch, $bits, $objdump, $objcopy, $cc,
+my ($arch, $endian, $bits, $objdump, $objcopy, $cc,
     $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV;
 
 # This file refers to mcount and shouldn't be ftraced, so lets' ignore it
@@ -216,9 +216,18 @@ if ($arch eq "x86_64") {
 
 } elsif ($arch eq "mips") {
 	$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
-	$ld .= " -melf".$bits."btsmip";
+	$objdump .= " -Melf-trad".$endian."mips ";
 
-	$cc .= " -mno-abicalls -fno-pic ";
+	if ($endian eq "big") {
+		$endian = " -EB ";
+		$ld .= " -melf".$bits."btsmip";
+	} else {
+		$endian = " -EL ";
+		$ld .= " -melf".$bits."ltsmip";
+	}
+
+	$cc .= " -mno-abicalls -fno-pic -mabi=" . $bits . $endian;
+	$ld .= $endian;
 
     if ($bits == 64) {
 		$type = ".dword";
Signature · 1 line
1.6.0.4
maintainer
#13 lore raw

Re: [PATCH v2 3/6] add an endian argument to scripts/recordmcount.pl

Quoted 4 lines · On Fri, 29 May 2009, [email protected] wrote:

From: Wu Zhangjin <[email protected]>

mips architecture need this argument to handle big/little endian differently.

Actually, I was thinking that you add this before adding the mips code. That way we don't add a broken mips code first.

So could you swap this with patch 2?

-- Steve

Quoted 3 lines
#14 lore raw

PATCH v2 4/6 mips function graph tracer support

In reply to [email protected]

From: Wu Zhangjin <[email protected]>

this works something like -finstrument-functions does, instead of using

void __cyg_profile_func_enter (void *this_fn,
void *call_site);
void __cyg_profile_func_exit (void *this_fn,
void *call_site);

-pg use _mcount, so some tricks are adoptive by the author of orignal function graph tracer:

the _mcount function will call prepare_function_return to save the parent_ip, ip and calltime in a tracing array, if success, the address of a hooker function named return_to_handler will be substitued to the parent_ip, so, after return from _mcount it will call the return_to_handler, not back to the parent_ip, but calling ftrace_return_to_handler to remember the rettime, and return the parent_ip to let return_to_handler go back to the real parent.

---
 arch/mips/Kconfig              |    1 +
 arch/mips/kernel/ftrace.c      |   72 ++++++++++++++++++++++++++++++++++++++++
 arch/mips/kernel/mcount.S      |   58 +++++++++++++++++++++++++++++++-
 arch/mips/kernel/vmlinux.lds.S |    1 +
 4 files changed, 131 insertions(+), 1 deletions(-)
arch/mips/Kconfig +1 -0
index 0c00536..ac1437e 100644
@@ -9,6 +9,7 @@ config MIPS
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
+	select HAVE_FUNCTION_GRAPH_TRACER
 	# Horrible source of confusion.  Die, die, die ...
 	select EMBEDDED
 	select RTC_LIB
arch/mips/kernel/ftrace.c +72 -0

75 lines not on this page · raw message

arch/mips/kernel/mcount.S +57 -1

87 lines not on this page · raw message

arch/mips/kernel/vmlinux.lds.S +1 -0
index 58738c8..67435e5 100644
@@ -36,6 +36,7 @@ SECTIONS
 		SCHED_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
+		IRQENTRY_TEXT
 		*(.text.*)
 		*(.fixup)
 		*(.gnu.warning)
Signature · 1 line
1.6.0.4
#15 lore raw

PATCH v2 5/6 mips specific clock function to get precise timestamp

In reply to [email protected]

From: Wu Zhangjin <[email protected]>

by default, trace_clock_local calling sched_clock(jiffies-based) to get timestamp, in x86, there is a tsc(64bit) based sched_clock, but in mips, the 'tsc'(clock counter) is only 32bit long, which will easily rollover, and there is no existing high precise sched_clock in mips, we need to get one ourselves.

to avoid invading the whole linux-mips, i do not want to implement a tsc-based native_sched_clock instead of sched_clock like x86 does. because, there is a need to handling rollover of the only 32-bit long 'tsc' of mips, which will need extra overhead. in reality, i have tried to do it, but made the kernel hangs when booting, I'm not sure why it not work.

so, I just implement a native_sched_clock in arch/mips/kernel/ftrace.c, but not override the original sched_clock(). to get high precise timestamp, we implement a native_trace_clock_local, which will not call original sched_clock again, but native_sched_clock().

and what about the trace_clock and trace_clock_global function, should we also implement a mips-secific one? I'm not sure.

---
 arch/mips/kernel/Makefile       |    2 +
 arch/mips/kernel/csrc-r4k.c     |    2 +-
 arch/mips/kernel/ftrace_clock.c |   71 +++++++++++++++++++++++++++++++++++++++
 kernel/trace/trace_clock.c      |    2 +-
 4 files changed, 75 insertions(+), 2 deletions(-)
 create mode 100644 arch/mips/kernel/ftrace_clock.c
arch/mips/kernel/Makefile +2 -0
index 8dabcc6..44ec7e0 100644
@@ -11,6 +11,7 @@ obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 ifdef CONFIG_FUNCTION_TRACER
 # Do not profile debug and lowlevel utilities
 CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_ftrace_clock.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
@@ -32,6 +33,7 @@ obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
 obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o
+obj-$(CONFIG_NOP_TRACER)	+= ftrace_clock.o
 
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
 obj-$(CONFIG_CPU_MIPS32)	+= r4k_fpu.o r4k_switch.o
arch/mips/kernel/csrc-r4k.c +1 -1
index e95a3cd..3da1c7a 100644
@@ -10,7 +10,7 @@
 
 #include <asm/time.h>
 
-static cycle_t c0_hpt_read(struct clocksource *cs)
+static cycle_t notrace c0_hpt_read(struct clocksource *cs)
 {
 	return read_c0_count();
 }
arch/mips/kernel/ftrace_clock.c new file +71 -0

71 lines not on this page · raw message

kernel/trace/trace_clock.c +1 -1
index b588fd8..78c98c8 100644
@@ -26,7 +26,7 @@
  * Useful for tracing that does not cross to other CPUs nor
  * does it go through idle events.
  */
-u64 notrace trace_clock_local(void)
+u64 __attribute__((weak)) notrace trace_clock_local(void)
 {
 	unsigned long flags;
 	u64 clock;
Signature · 1 line
1.6.0.4
#16 lore raw

PATCH v2 6/6 mips specific system call tracer

In reply to [email protected]

From: Wu Zhangjin <[email protected]>

FIXME: there are several different sys_call_entry in mips64, but currently, i only use the the one in arch/mips/kernel/scall64-o32.S so,if people not use o32 standard, it will not compiled normally.

the system call tracing demo in a debian system on qemu-system-mipsel/malta:

debian-mips-malta:~# mount -t debugfs nodev /debug
debian-mips-malta:~# echo 20000 > /debug/tracing/buffer_size_kb
debian-mips-malta:~# cat /debug/tracing/available_tracers
syscall nop
debian-mips-malta:~# echo syscall > /debug/tracing/current_tracer
debian-mips-malta:~# echo 1 > /debug/tracing/tracing_enabled
debian-mips-malta:~# sleep 1
debian-mips-malta:~# echo 0 > /debug/tracing/tracing_enabled
debian-mips-malta:~# cat /debug/tracing/trace | head -20
           <...>-533   [000]    60.458291: sys_write(fd: 1, buf: 4fc408, count: 8)
           <...>-533   [000]    64.325614: sys_getrlimit(resource: 3, rlim: 530020)
           <...>-533   [000]    64.327089: sys_read(fd: 2, buf: 4fc008, count: 6)
           <...>-533   [000]    64.969663: sys_exit(error_code: 2)
           <...>-533   [000]    65.608794: sys_exit(error_code: 2)
           <...>-533   [000]    66.231796: sys_read(fd: 2, buf: 4fc008, count: 6)
           <...>-533   [000]    66.913687: sys_open(filename: 1, flags: 0, mode: a)
           <...>-533   [000]    66.914617: sys_exit(error_code: 1)
           <...>-533   [000]    70.797507: sys_exit(error_code: 503be8)
           <...>-536   [000]    70.833108: sys_exit(error_code: 2aac6cfc)
           <...>-536   [000]    70.833897: sys_exit(error_code: 2aac6540)
           <...>-536   [000]    70.835711: sys_exit(error_code: 2aac6cfc)
           <...>-536   [000]    70.840609: sys_lchown(filename: 3, user: 7fb08b38, group: 20)
           <...>-533   [000]    71.877785: sys_open(filename: ffffffff, flags: 7fcf08c8, mode: b)
           <...>-533   [000]    75.531122: sys_open(filename: 1, flags: 0, mode: a)
---
 arch/mips/Kconfig                   |    1 +
 arch/mips/include/asm/ptrace.h      |    2 +
 arch/mips/include/asm/reg.h         |    5 ++
 arch/mips/include/asm/syscall.h     |   84 +++++++++++++++++++++++++++++++++++
 arch/mips/include/asm/thread_info.h |    5 ++-
 arch/mips/kernel/Makefile           |    1 +
 arch/mips/kernel/entry.S            |    2 +-
 arch/mips/kernel/ftrace.c           |   71 +++++++++++++++++++++++++++++
 arch/mips/kernel/ptrace.c           |   14 +++++-
 arch/mips/kernel/scall64-o32.S      |    2 +-
 10 files changed, 182 insertions(+), 5 deletions(-)
 create mode 100644 arch/mips/include/asm/syscall.h
arch/mips/Kconfig +1 -0
index ac1437e..f488027 100644
@@ -10,6 +10,7 @@ config MIPS
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
 	select HAVE_FUNCTION_GRAPH_TRACER
+	select HAVE_FTRACE_SYSCALLS
 	# Horrible source of confusion.  Die, die, die ...
 	select EMBEDDED
 	select RTC_LIB
arch/mips/include/asm/ptrace.h +2 -0
index ce47118..32e5b62 100644
@@ -45,6 +45,8 @@ struct pt_regs {
 	unsigned long cp0_badvaddr;
 	unsigned long cp0_cause;
 	unsigned long cp0_epc;
+	/* Used for restarting system calls */
+	unsigned long orig_v0;
 #ifdef CONFIG_MIPS_MT_SMTC
 	unsigned long cp0_tcstatus;
 #endif /* CONFIG_MIPS_MT_SMTC */
arch/mips/include/asm/reg.h +5 -0
index 634b55d..93d66bc 100644
@@ -65,6 +65,8 @@
 #define EF_CP0_CAUSE		43
 #define EF_UNUSED0		44
 
+#define EF_ORIG_V0		45
+
 #define EF_SIZE			180
 
 #endif
@@ -121,6 +123,9 @@
 #define EF_CP0_STATUS		36
 #define EF_CP0_CAUSE		37
 
+
+#define EF_ORIG_V0			38
+
 #define EF_SIZE			304	/* size in bytes */
 
 #endif /* CONFIG_64BIT */
arch/mips/include/asm/syscall.h new file +84 -0

84 lines not on this page · raw message

arch/mips/include/asm/thread_info.h +4 -1
index 143a481..1d55dc0 100644
@@ -128,6 +128,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_32BIT_ADDR		23	/* 32-bit address space (o32/n32) */
 #define TIF_FPUBOUND		24	/* thread bound to FPU-full CPU set */
 #define TIF_LOAD_WATCH		25	/* If set, load watch registers */
+#define TIF_SYSCALL_FTRACE	27	/* for ftrace syscall instrumentation */
 #define TIF_SYSCALL_TRACE	31	/* syscall trace active */
 
 #ifdef CONFIG_MIPS32_O32
@@ -151,11 +152,13 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_32BIT_ADDR		(1<<TIF_32BIT_ADDR)
 #define _TIF_FPUBOUND		(1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH		(1<<TIF_LOAD_WATCH)
+#define _TIF_SYSCALL_FTRACE	(1<<TIF_SYSCALL_FTRACE)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK		(0x0000ffef & ~_TIF_SECCOMP)
 /* work to do on any return to u-space */
-#define _TIF_ALLWORK_MASK	(0x8000ffff & ~_TIF_SECCOMP)
+#define _TIF_ALLWORK_MASK	\
+	((0x8000ffff & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE)
 
 #endif /* __KERNEL__ */
 
arch/mips/kernel/Makefile +1 -0
index 44ec7e0..1114c85 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MODULES)		+= mips_ksyms.o module.o
 
 obj-$(CONFIG_FUNCTION_TRACER)	+= mcount.o
 obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS)	+= ftrace.o
 obj-$(CONFIG_NOP_TRACER)	+= ftrace_clock.o
 
 obj-$(CONFIG_CPU_LOONGSON2)	+= r4k_fpu.o r4k_switch.o
arch/mips/kernel/entry.S +1 -1
index ffa3310..786e4ef 100644
@@ -167,7 +167,7 @@ work_notifysig:				# deal with pending signals and
 FEXPORT(syscall_exit_work_partial)
 	SAVE_STATIC
 syscall_exit_work:
-	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SYSCALL_FTRACE
 	and	t0, a2			# a2 is preloaded with TI_FLAGS
 	beqz	t0, work_pending	# trace bit set?
 	local_irq_enable		# could let do_syscall_trace()
arch/mips/kernel/ftrace.c +71 -0

80 lines not on this page · raw message

arch/mips/kernel/ptrace.c +12 -2
index 054861c..fa762dc 100644
@@ -25,6 +25,7 @@
 #include <linux/security.h>
 #include <linux/audit.h>
 #include <linux/seccomp.h>
+#include <linux/ftrace.h>
 
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
@@ -39,6 +40,7 @@
 #include <asm/bootinfo.h>
 #include <asm/reg.h>
 
+#include <trace/syscall.h>
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -60,7 +62,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data)
 	struct pt_regs *regs;
 	int i;
 
-	if (!access_ok(VERIFY_WRITE, data, 38 * 8))
+	if (!access_ok(VERIFY_WRITE, data, 39 * 8))
 		return -EIO;
 
 	regs = task_pt_regs(child);
@@ -73,6 +75,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data)
 	__put_user((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0);
 	__put_user((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0);
 	__put_user((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0);
+	__put_user((long)regs->orig_v0, data + EF_ORIG_V0 - EF_R0);
 
 	return 0;
 }
@@ -87,7 +90,7 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
 	struct pt_regs *regs;
 	int i;
 
-	if (!access_ok(VERIFY_READ, data, 38 * 8))
+	if (!access_ok(VERIFY_READ, data, 39 * 8))
 		return -EIO;
 
 	regs = task_pt_regs(child);
@@ -97,6 +100,7 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
 	__get_user(regs->lo, data + EF_LO - EF_R0);
 	__get_user(regs->hi, data + EF_HI - EF_R0);
 	__get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0);
+	__get_user(regs->orig_v0, data + EF_ORIG_V0 - EF_R0);
 
 	/* badvaddr, status, and cause may not be written.  */
 
@@ -575,6 +579,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 	if (!(current->ptrace & PT_PTRACED))
 		goto out;
 
+	if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+		ftrace_syscall_exit(regs);
+
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		goto out;
 
@@ -594,6 +601,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 	}
 
 out:
+	if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
+		ftrace_syscall_enter(regs);
+
 	if (unlikely(current->audit_context) && !entryexit)
 		audit_syscall_entry(audit_arch(), regs->regs[0],
 				    regs->regs[4], regs->regs[5],
arch/mips/kernel/scall64-o32.S +1 -1
index a5598b2..dd1f13a 100644
@@ -202,7 +202,7 @@ einval:	li	v0, -ENOSYS
 
 	.align	3
 	.type	sys_call_table,@object
-sys_call_table:
+EXPORT(sys_call_table)
 	PTR	sys32_syscall			/* 4000 */
 	PTR	sys_exit
 	PTR	sys_fork
Signature · 1 line
1.6.0.4