[Sheepdog] [RFC PATCH 07/11] trace: add return hooker

Liu Yuan namei.unix at gmail.com
Tue Jan 17 12:59:58 CET 2012


From: Liu Yuan <tailai.ly at taobao.com>


Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
---
 sheep/trace/graph.c  |   85 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sheep/trace/mcount.S |   16 +++++++++-
 sheep/trace/trace.h  |   17 ++++++++++
 3 files changed, 117 insertions(+), 1 deletions(-)
 create mode 100644 sheep/trace/graph.c

diff --git a/sheep/trace/graph.c b/sheep/trace/graph.c
new file mode 100644
index 0000000..01aa4ba
--- /dev/null
+++ b/sheep/trace/graph.c
@@ -0,0 +1,85 @@
+#include <time.h>
+
+#include "trace.h"
+#include "logger.h"
+#include "util.h"
+
+static __thread unsigned ret_stack_index;
+static __thread struct trace_ret_stack {
+	unsigned long ret;
+	unsigned long func;
+	unsigned long long entry_time;
+} trace_ret_stack[100]; /* FIXME: consider stack overrun */
+
+static void push_return_trace(unsigned long ret, unsigned long long etime,
+		unsigned long func, int *depth)
+{
+	trace_ret_stack[ret_stack_index].ret = ret;
+	trace_ret_stack[ret_stack_index].func = func;
+	trace_ret_stack[ret_stack_index].entry_time = etime;
+	*depth = ret_stack_index;
+	ret_stack_index++;
+}
+
+static void pop_return_trace(struct trace_graph_ret *trace, unsigned long *ret_func)
+{
+	ret_stack_index--;
+	trace->func = trace_ret_stack[ret_stack_index].func;
+	trace->entry_time = trace_ret_stack[ret_stack_index].entry_time;
+	*ret_func = trace_ret_stack[ret_stack_index].ret;
+	trace->depth = ret_stack_index;
+}
+
+static notrace uint64_t clock_get_time(void)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	return (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec;
+}
+
+static notrace void default_trace_graph_return(struct trace_graph_ret *trace)
+{
+	struct ipinfo info;
+	if (get_ipinfo(trace->func, &info) < 0)
+		dprintf("0x%lx not found\n", trace->func);
+
+	dprintf("%.*s: %llu (ns)\n", info.fn_namelen, info.fn_name, trace->return_time - trace->entry_time);
+}
+
+static trace_func_graph_ent_t trace_graph_entry;
+static trace_func_graph_ret_t trace_graph_return = default_trace_graph_return;
+
+notrace unsigned long trace_return_call(void)
+{
+	struct trace_graph_ret trace;
+	unsigned long ret;
+
+	pop_return_trace(&trace, &ret);
+	trace.return_time = clock_get_time();
+	if (trace_graph_return)
+		trace_graph_return(&trace);
+
+	return ret;
+}
+
+/* Hook the return address and push it in the trace_ret_stack.
+ *
+ * ip: the address of the call instruction in the code.
+ * ret_addr: the address of return address in the stack frame.
+ */
+static notrace void graph_tracer(unsigned long ip, unsigned long *ret_addr)
+{
+	unsigned long old_addr = *ret_addr;
+	uint64_t entry_time;
+	struct trace_graph_ent trace;
+
+	*ret_addr = (unsigned long)trace_return_caller;
+	entry_time = clock_get_time();
+	push_return_trace(old_addr, entry_time, ip, &trace.depth);
+	trace.func = ip;
+	if (trace_graph_entry)
+		trace_graph_entry(&trace);
+}
+
+register_tracer(graph_tracer);
diff --git a/sheep/trace/mcount.S b/sheep/trace/mcount.S
index 5f1e6b5..69c99ca 100644
--- a/sheep/trace/mcount.S
+++ b/sheep/trace/mcount.S
@@ -45,7 +45,7 @@ ENTRY(trace_caller)
 	movq %r9, 48(%rsp)
 
 	movq 0x38(%rsp), %rdi
-	movq 8(%rbp), %rsi
+	leaq 8(%rbp), %rsi
 	subq $INSN_SIZE, %rdi
 
 .globl trace_call
@@ -65,6 +65,20 @@ trace_call:
 trace_stub:
 	retq
 
+ENTRY(trace_return_caller)
+	subq  $24, %rsp
+
+	movq %rax, (%rsp)
+	movq %rdx, 8(%rsp)
+
+	call trace_return_call
+
+	movq %rax, %rdi
+	movq 8(%rsp), %rdx
+	movq (%rsp), %rax
+	addq $24, %rsp
+	jmp *%rdi
+
 .globl NOP5
 NOP5:
 	.byte 0x0f,0x1f,0x44,0x00,0x00 # Intel recommended one for 5 bytes nops
diff --git a/sheep/trace/trace.h b/sheep/trace/trace.h
index 5dcbca5..d2b2c63 100644
--- a/sheep/trace/trace.h
+++ b/sheep/trace/trace.h
@@ -26,7 +26,22 @@ struct caller {
 	const char *name;
 };
 
+struct trace_graph_ent {
+        unsigned long func; /* Current function */
+        int depth;
+};
+
+struct trace_graph_ret {
+        unsigned long func; /* Current function */
+        unsigned long long entry_time;
+        unsigned long long return_time;
+        int depth;
+};
+
 typedef void (*trace_func_t)(unsigned long ip, unsigned long *parent_ip);
+/* Type of the callback handlers for function entry and return */
+typedef void (*trace_func_graph_ret_t)(struct trace_graph_ret *);
+typedef void (*trace_func_graph_ent_t)(struct trace_graph_ent *);
 
 /* stabs.c */
 extern int get_ipinfo(unsigned long ip, struct ipinfo *info);
@@ -37,6 +52,8 @@ extern void mcount_call(void);
 extern void trace_caller(void);
 extern void trace_call(unsigned long, unsigned long *);
 extern const unsigned char NOP5[];
+extern void trace_return_caller(void);
+extern unsigned long trace_return_call(void);
 
 /* trace.c */
 extern pthread_cond_t trace_cond;
-- 
1.7.8.2




More information about the sheepdog mailing list