linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry
@ 2012-04-26  2:29 Steven Rostedt
  2012-04-26  2:29 ` [PATCH 1/6][RFC] ftrace: Sort all function addresses, not just per page Steven Rostedt
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 1750 bytes --]

As I want to add the -mfentry to allow for function tracing without
frame pointers (as some distros are now disabling function tracing :-(

I have to handle the case that a kprobe is placed on a ftrace nop.
As ftrace nops with -mfentry will be the first instruction of a
function, it being the location of a kprobe is a likely occurrence.

Ideally, kprobes would just use the function tracing infrastructure
to make an automatic optimized jump. But that is for another day as it
requires a bit of work in the function tracer to handle regs and such.

So the quick fix for now is to simply move the probe to the next
instruction after the ftrace nop. As the nop shouldn't be doing anything
anyway (and tracing should return to the function in the same state)
moving the location of the probe should not cause any harm.

The first 5 patches are non controversial, and could probably just be
pushed for 3.5 inclusion. The last patch makes the change to move the
probe to the next instruction after the ftrace nop.

Anyone see any problem with this?

-- Steve


Steven Rostedt (6):
      ftrace: Sort all function addresses, not just per page
      ftrace: Remove extra helper functions
      ftrace: Speed up search by skipping pages by address
      ftrace: Consolidate ftrace_location() and ftrace_text_reserved()
      ftrace: Return record ip addr for ftrace_location()
      kprobes: Allow probe on ftrace reserved text (but move it)

----
 include/asm-generic/vmlinux.lds.h |    2 +-
 include/linux/ftrace.h            |    2 +-
 kernel/kprobes.c                  |   11 ++-
 kernel/trace/ftrace.c             |  173 ++++++++++++++++++++-----------------
 4 files changed, 104 insertions(+), 84 deletions(-)

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/6][RFC] ftrace: Sort all function addresses, not just per page
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26  2:29 ` [PATCH 2/6][RFC] ftrace: Remove extra helper functions Steven Rostedt
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 2662 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Instead of just sorting the ip's of the functions per ftrace page,
sort the entire list before adding them to the ftrace pages.

This will allow the bsearch algorithm to be sped up as it can
also sort by pages, not just records within a page.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/asm-generic/vmlinux.lds.h |    2 +-
 kernel/trace/ftrace.c             |   34 ++++++++++++++++++++++------------
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8aeadf6..4e2e1cc 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -486,8 +486,8 @@
 	CPU_DISCARD(init.data)						\
 	MEM_DISCARD(init.data)						\
 	KERNEL_CTORS()							\
-	*(.init.rodata)							\
 	MCOUNT_REC()							\
+	*(.init.rodata)							\
 	FTRACE_EVENTS()							\
 	TRACE_SYSCALLS()						\
 	DEV_DISCARD(init.rodata)					\
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 0fa92f6..6a19e81 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3688,15 +3688,27 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
 	return 0;
 }
 
-static void ftrace_swap_recs(void *a, void *b, int size)
+static int ftrace_cmp_ips(const void *a, const void *b)
 {
-	struct dyn_ftrace *reca = a;
-	struct dyn_ftrace *recb = b;
-	struct dyn_ftrace t;
+	const unsigned long *ipa = a;
+	const unsigned long *ipb = b;
 
-	t = *reca;
-	*reca = *recb;
-	*recb = t;
+	if (*ipa > *ipb)
+		return 1;
+	if (*ipa < *ipb)
+		return -1;
+	return 0;
+}
+
+static void ftrace_swap_ips(void *a, void *b, int size)
+{
+	unsigned long *ipa = a;
+	unsigned long *ipb = b;
+	unsigned long t;
+
+	t = *ipa;
+	*ipa = *ipb;
+	*ipb = t;
 }
 
 static int ftrace_process_locs(struct module *mod,
@@ -3715,6 +3727,9 @@ static int ftrace_process_locs(struct module *mod,
 	if (!count)
 		return 0;
 
+	sort(start, count, sizeof(*start),
+	     ftrace_cmp_ips, ftrace_swap_ips);
+
 	pg = ftrace_allocate_pages(count);
 	if (!pg)
 		return -ENOMEM;
@@ -3762,11 +3777,6 @@ static int ftrace_process_locs(struct module *mod,
 	/* These new locations need to be initialized */
 	ftrace_new_pgs = pg;
 
-	/* Make each individual set of pages sorted by ips */
-	for (; pg; pg = pg->next)
-		sort(pg->records, pg->index, sizeof(struct dyn_ftrace),
-		     ftrace_cmp_recs, ftrace_swap_recs);
-
 	/*
 	 * We only need to disable interrupts on start up
 	 * because we are modifying code that an interrupt
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/6][RFC] ftrace: Remove extra helper functions
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
  2012-04-26  2:29 ` [PATCH 1/6][RFC] ftrace: Sort all function addresses, not just per page Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26  2:29 ` [PATCH 3/6][RFC] ftrace: Speed up search by skipping pages by address Steven Rostedt
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 3411 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

The ftrace_record_ip() and ftrace_alloc_dyn_node() were from the
time of the ftrace daemon. Although they were still used, they
still make things a bit more complex than necessary.

Move the code into the one function that uses it, and remove the
helper functions.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c |   61 +++++++++++++++++++------------------------------
 1 file changed, 24 insertions(+), 37 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6a19e81..4e608f8 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1520,35 +1520,6 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
 	__ftrace_hash_rec_update(ops, filter_hash, 1);
 }
 
-static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
-{
-	if (ftrace_pages->index == ftrace_pages->size) {
-		/* We should have allocated enough */
-		if (WARN_ON(!ftrace_pages->next))
-			return NULL;
-		ftrace_pages = ftrace_pages->next;
-	}
-
-	return &ftrace_pages->records[ftrace_pages->index++];
-}
-
-static struct dyn_ftrace *
-ftrace_record_ip(unsigned long ip)
-{
-	struct dyn_ftrace *rec;
-
-	if (ftrace_disabled)
-		return NULL;
-
-	rec = ftrace_alloc_dyn_node(ip);
-	if (!rec)
-		return NULL;
-
-	rec->ip = ip;
-
-	return rec;
-}
-
 static void print_ip_ins(const char *fmt, unsigned char *p)
 {
 	int i;
@@ -3715,7 +3686,9 @@ static int ftrace_process_locs(struct module *mod,
 			       unsigned long *start,
 			       unsigned long *end)
 {
+	struct ftrace_page *start_pg;
 	struct ftrace_page *pg;
+	struct dyn_ftrace *rec;
 	unsigned long count;
 	unsigned long *p;
 	unsigned long addr;
@@ -3730,8 +3703,8 @@ static int ftrace_process_locs(struct module *mod,
 	sort(start, count, sizeof(*start),
 	     ftrace_cmp_ips, ftrace_swap_ips);
 
-	pg = ftrace_allocate_pages(count);
-	if (!pg)
+	start_pg = ftrace_allocate_pages(count);
+	if (!start_pg)
 		return -ENOMEM;
 
 	mutex_lock(&ftrace_lock);
@@ -3744,7 +3717,7 @@ static int ftrace_process_locs(struct module *mod,
 	if (!mod) {
 		WARN_ON(ftrace_pages || ftrace_pages_start);
 		/* First initialization */
-		ftrace_pages = ftrace_pages_start = pg;
+		ftrace_pages = ftrace_pages_start = start_pg;
 	} else {
 		if (!ftrace_pages)
 			goto out;
@@ -3755,11 +3728,11 @@ static int ftrace_process_locs(struct module *mod,
 				ftrace_pages = ftrace_pages->next;
 		}
 
-		ftrace_pages->next = pg;
-		ftrace_pages = pg;
+		ftrace_pages->next = start_pg;
 	}
 
 	p = start;
+	pg = start_pg;
 	while (p < end) {
 		addr = ftrace_call_adjust(*p++);
 		/*
@@ -3770,12 +3743,26 @@ static int ftrace_process_locs(struct module *mod,
 		 */
 		if (!addr)
 			continue;
-		if (!ftrace_record_ip(addr))
-			break;
+
+		if (pg->index == pg->size) {
+			/* We should have allocated enough */
+			if (WARN_ON(!pg->next))
+				break;
+			pg = pg->next;
+		}
+
+		rec = &pg->records[pg->index++];
+		rec->ip = addr;
 	}
 
+	/* We should have used all pages */
+	WARN_ON(pg->next);
+
+	/* Assign the last page to ftrace_pages */
+	ftrace_pages = pg;
+
 	/* These new locations need to be initialized */
-	ftrace_new_pgs = pg;
+	ftrace_new_pgs = start_pg;
 
 	/*
 	 * We only need to disable interrupts on start up
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/6][RFC] ftrace: Speed up search by skipping pages by address
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
  2012-04-26  2:29 ` [PATCH 1/6][RFC] ftrace: Sort all function addresses, not just per page Steven Rostedt
  2012-04-26  2:29 ` [PATCH 2/6][RFC] ftrace: Remove extra helper functions Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26  2:29 ` [PATCH 4/6][RFC] ftrace: Consolidate ftrace_location() and ftrace_text_reserved() Steven Rostedt
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 2041 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

As all records in a page of the ftrace table are sorted, we can
speed up the search algorithm by checking if the address to look for
falls in between the first and last record ip on the page.

This speeds up both the ftrace_location() and ftrace_text_reserved()
algorithms, as it can skip full pages when the search address is
not in them.

Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c |   22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 4e608f8..333f890 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1411,6 +1411,8 @@ int ftrace_location(unsigned long ip)
 	key.ip = ip;
 
 	for (pg = ftrace_pages_start; pg; pg = pg->next) {
+		if (ip < pg->records[0].ip || ip > pg->records[pg->index - 1].ip)
+			continue;
 		rec = bsearch(&key, pg->records, pg->index,
 			      sizeof(struct dyn_ftrace),
 			      ftrace_cmp_recs);
@@ -1571,16 +1573,24 @@ void ftrace_bug(int failed, unsigned long ip)
 
 
 /* Return 1 if the address range is reserved for ftrace */
-int ftrace_text_reserved(void *start, void *end)
+int ftrace_text_reserved(void *s, void *e)
 {
 	struct dyn_ftrace *rec;
 	struct ftrace_page *pg;
+	unsigned long start = (unsigned long)s;
+	unsigned long end = (unsigned long)e;
+	int i;
 
-	do_for_each_ftrace_rec(pg, rec) {
-		if (rec->ip <= (unsigned long)end &&
-		    rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start)
-			return 1;
-	} while_for_each_ftrace_rec();
+	for (pg = ftrace_pages_start; pg; pg = pg->next) {
+		if (end < pg->records[0].ip ||
+		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
+			continue;
+		for (i = 0; i < pg->index; i++) {
+			rec = &pg->records[i];
+			if (rec->ip <= end && rec->ip + MCOUNT_INSN_SIZE > start)
+				return 1;
+		}
+	}
 	return 0;
 }
 
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/6][RFC] ftrace: Consolidate ftrace_location() and ftrace_text_reserved()
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
                   ` (2 preceding siblings ...)
  2012-04-26  2:29 ` [PATCH 3/6][RFC] ftrace: Speed up search by skipping pages by address Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26  2:29 ` [PATCH 5/6][RFC] ftrace: Return record ip addr for ftrace_location() Steven Rostedt
  2012-04-26  2:29 ` [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it) Steven Rostedt
  5 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 4497 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Both ftrace_location() and ftrace_text_reserved() do basically the same thing.
They search to see if an address is in the ftace table (contains an address
that may change from nop to call ftrace_caller). The difference is
that ftrace_location() searches a single address, but ftrace_text_reserved()
searches a range.

This laso makes the ftrace_text_reserved() faster as it now uses a bsearch()
instead of linearly searching all the addresses within a page.

Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/trace/ftrace.c |   80 ++++++++++++++++++++++++-------------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 333f890..51e07f7 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1383,35 +1383,28 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
 
 static int ftrace_cmp_recs(const void *a, const void *b)
 {
-	const struct dyn_ftrace *reca = a;
-	const struct dyn_ftrace *recb = b;
+	const struct dyn_ftrace *key = a;
+	const struct dyn_ftrace *rec = b;
 
-	if (reca->ip > recb->ip)
-		return 1;
-	if (reca->ip < recb->ip)
+	if (key->flags < rec->ip)
 		return -1;
+	if (key->ip >= rec->ip + MCOUNT_INSN_SIZE)
+		return 1;
 	return 0;
 }
 
-/**
- * ftrace_location - return true if the ip giving is a traced location
- * @ip: the instruction pointer to check
- *
- * Returns 1 if @ip given is a pointer to a ftrace location.
- * That is, the instruction that is either a NOP or call to
- * the function tracer. It checks the ftrace internal tables to
- * determine if the address belongs or not.
- */
-int ftrace_location(unsigned long ip)
+static int ftrace_location_range(unsigned long start, unsigned long end)
 {
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
 	struct dyn_ftrace key;
 
-	key.ip = ip;
+	key.ip = start;
+	key.flags = end;	/* overload flags, as it is unsigned long */
 
 	for (pg = ftrace_pages_start; pg; pg = pg->next) {
-		if (ip < pg->records[0].ip || ip > pg->records[pg->index - 1].ip)
+		if (end < pg->records[0].ip ||
+		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
 			continue;
 		rec = bsearch(&key, pg->records, pg->index,
 			      sizeof(struct dyn_ftrace),
@@ -1423,6 +1416,36 @@ int ftrace_location(unsigned long ip)
 	return 0;
 }
 
+/**
+ * ftrace_location - return true if the ip giving is a traced location
+ * @ip: the instruction pointer to check
+ *
+ * Returns 1 if @ip given is a pointer to a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+int ftrace_location(unsigned long ip)
+{
+	return ftrace_location_range(ip, ip);
+}
+
+/**
+ * ftrace_text_reserved - return true if range contains an ftrace location
+ * @start: start of range to search
+ * @end: end of range to search (inclusive). @end points to the last byte to check.
+ *
+ * Returns 1 if @start and @end contains a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+int ftrace_text_reserved(void *start, void *end)
+{
+	return ftrace_location_range((unsigned long)start,
+				     (unsigned long)end);
+}
+
 static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
 				     int filter_hash,
 				     bool inc)
@@ -1571,29 +1594,6 @@ void ftrace_bug(int failed, unsigned long ip)
 	}
 }
 
-
-/* Return 1 if the address range is reserved for ftrace */
-int ftrace_text_reserved(void *s, void *e)
-{
-	struct dyn_ftrace *rec;
-	struct ftrace_page *pg;
-	unsigned long start = (unsigned long)s;
-	unsigned long end = (unsigned long)e;
-	int i;
-
-	for (pg = ftrace_pages_start; pg; pg = pg->next) {
-		if (end < pg->records[0].ip ||
-		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
-			continue;
-		for (i = 0; i < pg->index; i++) {
-			rec = &pg->records[i];
-			if (rec->ip <= end && rec->ip + MCOUNT_INSN_SIZE > start)
-				return 1;
-		}
-	}
-	return 0;
-}
-
 static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
 {
 	unsigned long flag = 0UL;
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/6][RFC] ftrace: Return record ip addr for ftrace_location()
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
                   ` (3 preceding siblings ...)
  2012-04-26  2:29 ` [PATCH 4/6][RFC] ftrace: Consolidate ftrace_location() and ftrace_text_reserved() Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26  2:29 ` [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it) Steven Rostedt
  5 siblings, 0 replies; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 3141 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

ftrace_location() is passed an addr, and returns 1 if the addr is
on a ftrace nop (or caller to ftrace_caller), and 0 otherwise.

To let kprobes know if it should move a breakpoint or not, it
must return the actual addr that is the start of the ftrace nop.
This way a kprobe placed on the location of a ftrace nop, can
instead be placed on the instruction after the nop. Even if the
probe addr is on the second or later byte of the nop, it can
simply be moved forward.

Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/ftrace.h |    2 +-
 kernel/trace/ftrace.c  |   16 ++++++++++------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 0b55903..9310993 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -295,7 +295,7 @@ struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
 int ftrace_update_record(struct dyn_ftrace *rec, int enable);
 int ftrace_test_record(struct dyn_ftrace *rec, int enable);
 void ftrace_run_stop_machine(int command);
-int ftrace_location(unsigned long ip);
+unsigned long ftrace_location(unsigned long ip);
 
 extern ftrace_func_t ftrace_trace_function;
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 51e07f7..7e3c398 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1393,7 +1393,7 @@ static int ftrace_cmp_recs(const void *a, const void *b)
 	return 0;
 }
 
-static int ftrace_location_range(unsigned long start, unsigned long end)
+static unsigned long ftrace_location_range(unsigned long start, unsigned long end)
 {
 	struct ftrace_page *pg;
 	struct dyn_ftrace *rec;
@@ -1410,7 +1410,7 @@ static int ftrace_location_range(unsigned long start, unsigned long end)
 			      sizeof(struct dyn_ftrace),
 			      ftrace_cmp_recs);
 		if (rec)
-			return 1;
+			return rec->ip;
 	}
 
 	return 0;
@@ -1420,12 +1420,12 @@ static int ftrace_location_range(unsigned long start, unsigned long end)
  * ftrace_location - return true if the ip giving is a traced location
  * @ip: the instruction pointer to check
  *
- * Returns 1 if @ip given is a pointer to a ftrace location.
+ * Returns rec->ip if @ip given is a pointer to a ftrace location.
  * That is, the instruction that is either a NOP or call to
  * the function tracer. It checks the ftrace internal tables to
  * determine if the address belongs or not.
  */
-int ftrace_location(unsigned long ip)
+unsigned long ftrace_location(unsigned long ip)
 {
 	return ftrace_location_range(ip, ip);
 }
@@ -1442,8 +1442,12 @@ int ftrace_location(unsigned long ip)
  */
 int ftrace_text_reserved(void *start, void *end)
 {
-	return ftrace_location_range((unsigned long)start,
-				     (unsigned long)end);
+	unsigned long ret;
+
+	ret = ftrace_location_range((unsigned long)start,
+				    (unsigned long)end);
+
+	return (int)!!ret;
 }
 
 static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it)
  2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
                   ` (4 preceding siblings ...)
  2012-04-26  2:29 ` [PATCH 5/6][RFC] ftrace: Return record ip addr for ftrace_location() Steven Rostedt
@ 2012-04-26  2:29 ` Steven Rostedt
  2012-04-26 10:12   ` Masami Hiramatsu
  5 siblings, 1 reply; 10+ messages in thread
From: Steven Rostedt @ 2012-04-26  2:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Masami Hiramatsu, Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 1777 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

If a probe is placed on a ftrace nop (or ftrace_caller), simply move the
probe to the next instruction instead of rejecting it. This will allow
kprobes not to be affected by ftrace using the -mfentry gcc option which
will put the ftrace nop at the beginning of the function. As a very common
case for kprobes is to add a probe to the very beginning of a function
we need a way to handle the case when ftrace takes the first instruction.

Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 kernel/kprobes.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index c62b854..560d80e 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1319,10 +1319,20 @@ int __kprobes register_kprobe(struct kprobe *p)
 	struct kprobe *old_p;
 	struct module *probed_mod;
 	kprobe_opcode_t *addr;
+	unsigned long ftrace_addr;
 
 	addr = kprobe_addr(p);
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
+
+	/*
+	 * If the address is located on a ftrace nop, set the
+	 * breakpoint to the following instruction.
+	 */
+	ftrace_addr = ftrace_location((unsigned long)addr);
+	if (unlikely(ftrace_addr))
+		addr = (kprobe_opcode_t *)(ftrace_addr + MCOUNT_INSN_SIZE);
+
 	p->addr = addr;
 
 	ret = check_kprobe_rereg(p);
@@ -1333,7 +1343,6 @@ int __kprobes register_kprobe(struct kprobe *p)
 	preempt_disable();
 	if (!kernel_text_address((unsigned long) p->addr) ||
 	    in_kprobes_functions((unsigned long) p->addr) ||
-	    ftrace_text_reserved(p->addr, p->addr) ||
 	    jump_label_text_reserved(p->addr, p->addr)) {
 		ret = -EINVAL;
 		goto cannot_probe;
-- 
1.7.9.5



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it)
  2012-04-26  2:29 ` [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it) Steven Rostedt
@ 2012-04-26 10:12   ` Masami Hiramatsu
  2012-04-27 14:01     ` Steven Rostedt
  0 siblings, 1 reply; 10+ messages in thread
From: Masami Hiramatsu @ 2012-04-26 10:12 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Frederic Weisbecker,
	yrl.pp-manager.tt

(2012/04/26 11:29), Steven Rostedt wrote:
> From: Steven Rostedt <srostedt@redhat.com>
> 
> If a probe is placed on a ftrace nop (or ftrace_caller), simply move the
> probe to the next instruction instead of rejecting it. This will allow
> kprobes not to be affected by ftrace using the -mfentry gcc option which
> will put the ftrace nop at the beginning of the function. As a very common
> case for kprobes is to add a probe to the very beginning of a function
> we need a way to handle the case when ftrace takes the first instruction.

Hmm, I think you'd better introduce a flag(KPROBE_FLAG_MOVED) for
adjustment of probed IP address. Caller or handler can fixup its IP
or kprobes itself can do it.

> 
> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  kernel/kprobes.c |   11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> index c62b854..560d80e 100644
> --- a/kernel/kprobes.c
> +++ b/kernel/kprobes.c
> @@ -1319,10 +1319,20 @@ int __kprobes register_kprobe(struct kprobe *p)
>  	struct kprobe *old_p;
>  	struct module *probed_mod;
>  	kprobe_opcode_t *addr;
> +	unsigned long ftrace_addr;
>  
>  	addr = kprobe_addr(p);
>  	if (IS_ERR(addr))
>  		return PTR_ERR(addr);
> +
> +	/*
> +	 * If the address is located on a ftrace nop, set the
> +	 * breakpoint to the following instruction.
> +	 */
> +	ftrace_addr = ftrace_location((unsigned long)addr);
> +	if (unlikely(ftrace_addr))
> +		addr = (kprobe_opcode_t *)(ftrace_addr + MCOUNT_INSN_SIZE);

And also, you may need to use ftrace_text_reserved() here,
or need a void ftrace_location() function for CONFIG_DYNAMIC_FTRACE=n.

> +
>  	p->addr = addr;
>  
>  	ret = check_kprobe_rereg(p);
> @@ -1333,7 +1343,6 @@ int __kprobes register_kprobe(struct kprobe *p)
>  	preempt_disable();
>  	if (!kernel_text_address((unsigned long) p->addr) ||
>  	    in_kprobes_functions((unsigned long) p->addr) ||
> -	    ftrace_text_reserved(p->addr, p->addr) ||
>  	    jump_label_text_reserved(p->addr, p->addr)) {
>  		ret = -EINVAL;
>  		goto cannot_probe;

Thanks,


-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it)
  2012-04-26 10:12   ` Masami Hiramatsu
@ 2012-04-27 14:01     ` Steven Rostedt
  2012-04-27 15:29       ` Frank Ch. Eigler
  0 siblings, 1 reply; 10+ messages in thread
From: Steven Rostedt @ 2012-04-27 14:01 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Frederic Weisbecker,
	yrl.pp-manager.tt

On Thu, 2012-04-26 at 19:12 +0900, Masami Hiramatsu wrote:

> Hmm, I think you'd better introduce a flag(KPROBE_FLAG_MOVED) for
> adjustment of probed IP address. Caller or handler can fixup its IP
> or kprobes itself can do it.
> 

> And also, you may need to use ftrace_text_reserved() here,
> or need a void ftrace_location() function for CONFIG_DYNAMIC_FTRACE=n.

Hi Masami,

What do you think of this patch?

-- Steve

commit 648bb05a49dcf95b9dddd07e361023124357ea36
Author: Steven Rostedt <srostedt@redhat.com>
Date:   Wed Apr 25 14:28:22 2012 -0400

    kprobes: Allow probe on ftrace reserved text (but move it)
    
    If a probe is placed on a ftrace nop (or ftrace_caller), simply move the
    probe to the next instruction instead of rejecting it. This will allow
    kprobes not to be affected by ftrace using the -mfentry gcc option which
    will put the ftrace nop at the beginning of the function. As a very common
    case for kprobes is to add a probe to the very beginning of a function
    we need a way to handle the case when ftrace takes the first instruction.
    
    Added KPROBE_FLAG_MOVED (as suggested by Masami) that is set when the address
    is moved to get around an ftrace nop.
    
    Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
    Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9310993..211ae45 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -414,6 +414,8 @@ static inline int ftrace_text_reserved(void *start, void *end)
 #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
 #define ftrace_free_filter(ops) do { } while (0)
 
+static inline unsigned long ftrace_location(unsigned long ip) { return 0; }
+
 static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
 			    size_t cnt, loff_t *ppos) { return -ENODEV; }
 static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index b6e1f8c..23cf41e 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -128,6 +128,7 @@ struct kprobe {
 				   * NOTE:
 				   * this flag is only for optimized_kprobe.
 				   */
+#define KPROBE_FLAG_MOVED	8 /* probe was moved passed ftrace nop */
 
 /* Has this kprobe gone ? */
 static inline int kprobe_gone(struct kprobe *p)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index c62b854..952619b 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1319,10 +1319,22 @@ int __kprobes register_kprobe(struct kprobe *p)
 	struct kprobe *old_p;
 	struct module *probed_mod;
 	kprobe_opcode_t *addr;
+	unsigned long ftrace_addr;
 
 	addr = kprobe_addr(p);
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
+
+	/*
+	 * If the address is located on a ftrace nop, set the
+	 * breakpoint to the following instruction.
+	 */
+	ftrace_addr = ftrace_location((unsigned long)addr);
+	if (unlikely(ftrace_addr)) {
+		addr = (kprobe_opcode_t *)(ftrace_addr + MCOUNT_INSN_SIZE);
+		p->flags |= KPROBE_FLAG_MOVED;
+	}
+
 	p->addr = addr;
 
 	ret = check_kprobe_rereg(p);
@@ -1333,7 +1345,6 @@ int __kprobes register_kprobe(struct kprobe *p)
 	preempt_disable();
 	if (!kernel_text_address((unsigned long) p->addr) ||
 	    in_kprobes_functions((unsigned long) p->addr) ||
-	    ftrace_text_reserved(p->addr, p->addr) ||
 	    jump_label_text_reserved(p->addr, p->addr)) {
 		ret = -EINVAL;
 		goto cannot_probe;



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it)
  2012-04-27 14:01     ` Steven Rostedt
@ 2012-04-27 15:29       ` Frank Ch. Eigler
  0 siblings, 0 replies; 10+ messages in thread
From: Frank Ch. Eigler @ 2012-04-27 15:29 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, linux-kernel, Ingo Molnar, Andrew Morton,
	Frederic Weisbecker, yrl.pp-manager.tt

Steven Rostedt <rostedt@goodmis.org> writes:

> [...]
> What do you think of this patch?
> [...]
> +	/*
> +	 * If the address is located on a ftrace nop, set the
> +	 * breakpoint to the following instruction.
> +	 */
> +	ftrace_addr = ftrace_location((unsigned long)addr);
> +	if (unlikely(ftrace_addr)) {
> +		addr = (kprobe_opcode_t *)(ftrace_addr + MCOUNT_INSN_SIZE);
> +		p->flags |= KPROBE_FLAG_MOVED;
> +	}
> [...]

I suspect Masami intended that this flag is later used during int3
processing to subtract MCOUNT_INSN_SIZE back out from the pt_regs->ip
during kprobe_handler() if this flag was set.

- FChE

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-04-27 15:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-26  2:29 [PATCH 0/6][RFC] tracing/kprobes: Get ready for -mfentry Steven Rostedt
2012-04-26  2:29 ` [PATCH 1/6][RFC] ftrace: Sort all function addresses, not just per page Steven Rostedt
2012-04-26  2:29 ` [PATCH 2/6][RFC] ftrace: Remove extra helper functions Steven Rostedt
2012-04-26  2:29 ` [PATCH 3/6][RFC] ftrace: Speed up search by skipping pages by address Steven Rostedt
2012-04-26  2:29 ` [PATCH 4/6][RFC] ftrace: Consolidate ftrace_location() and ftrace_text_reserved() Steven Rostedt
2012-04-26  2:29 ` [PATCH 5/6][RFC] ftrace: Return record ip addr for ftrace_location() Steven Rostedt
2012-04-26  2:29 ` [PATCH 6/6][RFC] kprobes: Allow probe on ftrace reserved text (but move it) Steven Rostedt
2012-04-26 10:12   ` Masami Hiramatsu
2012-04-27 14:01     ` Steven Rostedt
2012-04-27 15:29       ` Frank Ch. Eigler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).