Author: Lassi Tuura <lat@cern.ch>
Date:   2011-03-29 18:12:10 +0200

    Use light version of getcontext for fast trace.


---
 include/tdep-arm/libunwind_i.h    |    1 +
 include/tdep-hppa/libunwind_i.h   |    1 +
 include/tdep-ia64/libunwind_i.h   |    1 +
 include/tdep-mips/libunwind_i.h   |    1 +
 include/tdep-ppc32/libunwind_i.h  |    1 +
 include/tdep-ppc64/libunwind_i.h  |    1 +
 include/tdep-x86/libunwind_i.h    |    1 +
 include/tdep-x86_64/libunwind_i.h |    2 ++
 src/mi/backtrace.c                |    2 +-
 src/x86_64/getcontext.S           |   28 ++++++++++++++++++++++++++++
 tests/check-namespace.sh.in       |    1 +
 11 files changed, 39 insertions(+), 1 deletions(-)

diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index cd18292..271e1d3 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -215,6 +215,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 
 #endif /* !UNW_LOCAL_ONLY */
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h
index d5ba7ab..ef0bb5a 100644
--- a/include/tdep-hppa/libunwind_i.h
+++ b/include/tdep-hppa/libunwind_i.h
@@ -221,6 +221,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 
 #endif /* !UNW_LOCAL_ONLY */
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h
index ec20338..619425c 100644
--- a/include/tdep-ia64/libunwind_i.h
+++ b/include/tdep-ia64/libunwind_i.h
@@ -216,6 +216,7 @@ struct ia64_global_unwind_state
 # endif
   };
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	unw.needs_initialization
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h
index 17876d5..5713d95 100644
--- a/include/tdep-mips/libunwind_i.h
+++ b/include/tdep-mips/libunwind_i.h
@@ -276,6 +276,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 
 #endif /* !UNW_LOCAL_ONLY */
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h
index 23bf2d1..292da62 100644
--- a/include/tdep-ppc32/libunwind_i.h
+++ b/include/tdep-ppc32/libunwind_i.h
@@ -251,6 +251,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 				     1, c->as_arg);
 }
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h
index 5e96bee..31c9ccf 100644
--- a/include/tdep-ppc64/libunwind_i.h
+++ b/include/tdep-ppc64/libunwind_i.h
@@ -251,6 +251,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 				     1, c->as_arg);
 }
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h
index 739320e..1f2e144 100644
--- a/include/tdep-x86/libunwind_i.h
+++ b/include/tdep-x86/libunwind_i.h
@@ -237,6 +237,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 
 #endif /* !UNW_LOCAL_ONLY */
 
+#define tdep_getcontext_trace           unw_getcontext
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init			UNW_OBJ(init)
 /* Platforms that support UNW_INFO_FORMAT_TABLE need to define
diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h
index 906ab5d..c4c6960 100644
--- a/include/tdep-x86_64/libunwind_i.h
+++ b/include/tdep-x86_64/libunwind_i.h
@@ -177,6 +177,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
 				     1, c->as_arg);
 }
 
+#define tdep_getcontext_trace	        UNW_ARCH_OBJ(getcontext_trace)
 #define tdep_needs_initialization	UNW_OBJ(needs_initialization)
 #define tdep_init_mem_validate		UNW_OBJ(init_mem_validate)
 #define tdep_init			UNW_OBJ(init)
@@ -244,6 +245,7 @@ extern void tdep_stash_frame (struct dwarf_cursor *c,
 			      struct dwarf_reg_state *rs);
 #endif
 
+extern int tdep_getcontext_trace (unw_tdep_context_t *);
 extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n);
 
 #endif /* X86_64_LIBUNWIND_I_H */
diff --git a/src/mi/backtrace.c b/src/mi/backtrace.c
index cfaf639..bd748aa 100644
--- a/src/mi/backtrace.c
+++ b/src/mi/backtrace.c
@@ -61,7 +61,7 @@ unw_backtrace (void **buffer, int size)
   unw_context_t uc;
   int n = size;
 
-  unw_getcontext (&uc);
+  tdep_getcontext_trace (&uc);
 
   if (unlikely (unw_init_local (&cursor, &uc) < 0))
     return 0;
diff --git a/src/x86_64/getcontext.S b/src/x86_64/getcontext.S
index 15fff28..5befbe8 100644
--- a/src/x86_64/getcontext.S
+++ b/src/x86_64/getcontext.S
@@ -101,5 +101,33 @@ _Ux86_64_getcontext:
 	.cfi_endproc
 	.size _Ux86_64_getcontext, . - _Ux86_64_getcontext
 
+/*  int _Ux86_64_getcontext_trace (ucontext_t *ucp)
+
+  Saves limited machine context in UCP necessary for libunwind.
+  Unlike _Ux86_64_getcontext, saves only the parts needed for
+  fast trace. If fast trace fails, caller will have to get the
+  full context.
+*/
+
+	.global _Ux86_64_getcontext_trace
+	.type _Ux86_64_getcontext_trace, @function
+_Ux86_64_getcontext_trace:
+	.cfi_startproc
+
+	/* Save only RBP, RBX, RSP, RIP - exclude this call. */
+	movq %rbp, UC_MCONTEXT_GREGS_RBP(%rdi)
+	movq %rbx, UC_MCONTEXT_GREGS_RBX(%rdi)
+
+	leaq 8(%rsp), %rax
+	movq %rax, UC_MCONTEXT_GREGS_RSP(%rdi)
+
+	movq 0(%rsp), %rax
+	movq %rax, UC_MCONTEXT_GREGS_RIP(%rdi)
+
+	xorq	%rax, %rax
+	retq
+	.cfi_endproc
+	.size _Ux86_64_getcontext_trace, . - _Ux86_64_getcontext_trace
+
       /* We do not need executable stack.  */
       .section        .note.GNU-stack,"",@progbits
diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in
index 0608607..b9581bf 100644
--- a/tests/check-namespace.sh.in
+++ b/tests/check-namespace.sh.in
@@ -124,6 +124,7 @@ check_local_unw_abi () {
 	    match _U${plat}_is_fpreg
 	    match _UL${plat}_dwarf_search_unwind_table
 	    match _U${plat}_setcontext
+	    match _U${plat}_getcontext_trace
 	    ;;
 	*)
 	    match _U${plat}_is_fpreg
