On Mon, 22 Feb 2016 at 16:10:51 Arun Sharma wrote:
> The only known work around is to
> implement your own dl_iterate_phdr that doesn't call malloc by hooking
> into low level APIs that notify you every time a new shared object is
> loaded.

The attached patch adds the function 'unw_set_iterate_phdr_function' to the libunwind API, allowing a custom implementation of dl_iterate_phdr() to be hooked in. That implementation would need to maintain a local cache (or however else you wanted to manage it) to remove the need for taking the glibc loader lock.

Regards,
Jonathan Byrd
Senior Application Developer
Allinea Software Ltd.
Index: include/libunwind-common.h.in
===================================================================
--- include/libunwind-common.h.in.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/libunwind-common.h.in	2014-05-13 16:30:36.013906387 +0100
@@ -41,6 +41,7 @@
 # define UNW_PREFIX	UNW_PASTE(UNW_PASTE(_U,UNW_TARGET),_)
 #endif /* !UNW_LOCAL_ONLY */
 
+
 /* Error codes.  The unwind routines return the *negated* values of
    these error codes on error and a non-negative value on success.  */
 typedef enum
@@ -204,6 +205,19 @@
   }
 unw_save_loc_t;
 
+/* For struct dl_phdr_info to be defined when including link.h,
+ * _GNU_SOURCE define must be set (this then sets __USE_GNU, the
+ * guard used by link.h). */
+#ifndef _GNU_SOURCE
+#error "_GNU_SOURCE must be defined, either before including the \
+first header in the source .c file, or by defining it on \
+the command line (-D_GNU_SOURCE)"
+#endif
+#include <link.h>
+
+typedef int (*unw_iterate_phdr_callback_t) (struct dl_phdr_info *info, size_t size, void *data);
+typedef int (*unw_iterate_phdr_func_t) (unw_iterate_phdr_callback_t callback, void* data);
+
 /* These routines work both for local and remote unwinding.  */
 
 #define unw_local_addr_space	UNW_OBJ(local_addr_space)
@@ -226,6 +240,7 @@
 #define unw_get_proc_name	UNW_OBJ(get_proc_name)
 #define unw_set_caching_policy	UNW_OBJ(set_caching_policy)
 #define unw_get_caching_policy	UNW_OBJ(get_caching_policy)
+#define unw_set_iterate_phdr_function	UNW_OBJ(set_iterate_phdr_function)
 #define unw_regname		UNW_ARCH_OBJ(regname)
 #define unw_flush_cache		UNW_ARCH_OBJ(flush_cache)
 #define unw_strerror		UNW_ARCH_OBJ(strerror)
@@ -236,6 +251,7 @@
 extern void unw_flush_cache (unw_addr_space_t, unw_word_t, unw_word_t);
 extern int unw_set_caching_policy (unw_addr_space_t, unw_caching_policy_t);
 extern unw_caching_policy_t unw_get_caching_policy (unw_addr_space_t);
+extern void unw_set_iterate_phdr_function (unw_addr_space_t, unw_iterate_phdr_func_t);
 extern const char *unw_regname (unw_regnum_t);
 
 extern int unw_init_local (unw_cursor_t *, unw_context_t *);
Index: include/tdep-aarch64/libunwind_i.h
===================================================================
--- include/tdep-aarch64/libunwind_i.h.orig	2015-04-14 15:23:39.641876280 +0100
+++ include/tdep-aarch64/libunwind_i.h	2015-04-14 15:24:14.011876280 +0100
@@ -62,6 +62,7 @@
     struct unw_accessors acc;
     int big_endian;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-arm/libunwind_i.h
===================================================================
--- include/tdep-arm/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-arm/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -47,6 +47,7 @@
     struct unw_accessors acc;
     int big_endian;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-hppa/libunwind_i.h
===================================================================
--- include/tdep-hppa/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-hppa/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -46,6 +46,7 @@
   {
     struct unw_accessors acc;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-ia64/libunwind_i.h
===================================================================
--- include/tdep-ia64/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-ia64/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -97,6 +97,7 @@
     int big_endian;
     int abi;	/* abi < 0 => unknown, 0 => SysV, 1 => HP-UX, 2 => Windows */
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-mips/libunwind_i.h
===================================================================
--- include/tdep-mips/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-mips/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -54,6 +54,7 @@
     unsigned int addr_size;
 
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-ppc32/libunwind_i.h
===================================================================
--- include/tdep-ppc32/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-ppc32/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -52,6 +52,7 @@
 {
   struct unw_accessors acc;
   unw_caching_policy_t caching_policy;
+  unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
   AO_t cache_generation;
 #else
Index: include/tdep-ppc64/libunwind_i.h
===================================================================
--- include/tdep-ppc64/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-ppc64/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -54,6 +54,7 @@
   int big_endian;
   ppc64_abi_t abi;
   unw_caching_policy_t caching_policy;
+  unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
   AO_t cache_generation;
 #else
Index: include/tdep-sh/libunwind_i.h
===================================================================
--- include/tdep-sh/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-sh/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -47,6 +47,7 @@
     struct unw_accessors acc;
     int big_endian;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-x86/libunwind_i.h
===================================================================
--- include/tdep-x86/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-x86/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -46,6 +46,7 @@
   {
     struct unw_accessors acc;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: include/tdep-x86_64/libunwind_i.h
===================================================================
--- include/tdep-x86_64/libunwind_i.h.orig	2014-05-13 16:30:36.017906372 +0100
+++ include/tdep-x86_64/libunwind_i.h	2014-05-13 16:30:36.013906387 +0100
@@ -63,6 +63,7 @@
   {
     struct unw_accessors acc;
     unw_caching_policy_t caching_policy;
+    unw_iterate_phdr_func_t iterate_phdr_function;
 #ifdef HAVE_ATOMIC_OPS_H
     AO_t cache_generation;
 #else
Index: src/Makefile.am
===================================================================
--- src/Makefile.am.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/Makefile.am	2014-05-13 16:30:36.013906387 +0100
@@ -109,7 +109,8 @@
 	mi/Gput_dynamic_unwind_info.c mi/Gdestroy_addr_space.c		\
 	mi/Gget_reg.c mi/Gset_reg.c					\
 	mi/Gget_fpreg.c mi/Gset_fpreg.c					\
-	mi/Gset_caching_policy.c
+	mi/Gset_caching_policy.c					\
+	mi/Gset_iterate_phdr_function.c
 
 if SUPPORT_CXX_EXCEPTIONS
 libunwind_la_SOURCES_local_unwind =					\
@@ -137,7 +138,8 @@
 	mi/Lput_dynamic_unwind_info.c mi/Ldestroy_addr_space.c		\
 	mi/Lget_reg.c   mi/Lset_reg.c					\
 	mi/Lget_fpreg.c mi/Lset_fpreg.c					\
-	mi/Lset_caching_policy.c
+	mi/Lset_caching_policy.c					\
+	mi/Lset_iterate_phdr_function.c
 
 libunwind_la_SOURCES_local =						\
 	$(libunwind_la_SOURCES_local_nounwind)				\
Index: src/arm/Gex_tables.c
===================================================================
--- src/arm/Gex_tables.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/arm/Gex_tables.c	2014-05-13 16:30:36.013906387 +0100
@@ -520,7 +520,10 @@
       cb_data.di_debug.format = -1;
 
       SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
-      ret = dl_iterate_phdr (dwarf_callback, &cb_data);
+      if (as->iterate_phdr_function)
+          ret = as->iterate_phdr_function (dwarf_callback, &cb_data);
+      else
+          ret = dl_iterate_phdr (dwarf_callback, &cb_data);
       SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
 
       if (cb_data.single_fde)
@@ -544,7 +547,10 @@
       cb_data.di.format = -1;
 
       SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
-      ret = dl_iterate_phdr (arm_phdr_cb, &cb_data);
+      if (as->iterate_phdr_function)
+          ret = as->iterate_phdr_function (arm_phdr_cb, &cb_data);
+      else
+          ret = dl_iterate_phdr (arm_phdr_cb, &cb_data);
       SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
 
       if (cb_data.di.format != -1)
Index: src/arm/Ginit.c
===================================================================
--- src/arm/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/arm/Ginit.c	2014-05-13 16:30:36.013906387 +0100
@@ -166,6 +166,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = arm_find_proc_info;
   local_addr_space.acc.put_unwind_info = arm_put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/dwarf/Gfind_proc_info-lsb.c
===================================================================
--- src/dwarf/Gfind_proc_info-lsb.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/dwarf/Gfind_proc_info-lsb.c	2014-05-13 16:30:36.013906387 +0100
@@ -823,7 +823,10 @@
   cb_data.di_debug.format = -1;
 
   SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
-  ret = dl_iterate_phdr (dwarf_callback, &cb_data);
+  if (as->iterate_phdr_function)
+    ret = as->iterate_phdr_function (dwarf_callback, &cb_data);
+  else
+    ret = dl_iterate_phdr (dwarf_callback, &cb_data);
   SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
 
   if (ret <= 0)
Index: src/hppa/Ginit.c
===================================================================
--- src/hppa/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/hppa/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -180,6 +180,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/ia64/Ginit.c
===================================================================
--- src/ia64/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/ia64/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -362,6 +362,7 @@
   local_addr_space.abi = ABI_HPUX;
 #endif
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = tdep_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/ia64/Gtables.c
===================================================================
--- src/ia64/Gtables.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/ia64/Gtables.c	2014-05-13 16:30:36.017906372 +0100
@@ -624,7 +624,10 @@
   int ret;
 
   SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
-  ret = dl_iterate_phdr (check_callback, as);
+  if (as->iterate_phdr_function)
+    ret = as->iterate_phdr_function (check_callback, as);
+  else
+    ret = dl_iterate_phdr (check_callback, as);
   SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
   return ret;
 }
@@ -655,7 +658,10 @@
   di.u.ti.segbase = ip;	/* this is cheap... */
 
   SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &saved_mask);
-  ret = dl_iterate_phdr (callback, &di);
+  if (as->iterate_phdr_function)
+    ret = as->iterate_phdr_function (callback, &di);
+  else
+    ret = dl_iterate_phdr (callback, &di);
   SIGPROCMASK (SIG_SETMASK, &saved_mask, NULL);
 
   if (ret <= 0)
Index: src/mi/Gset_iterate_phdr_function.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/mi/Gset_iterate_phdr_function.c	2014-05-13 16:30:36.017906372 +0100
@@ -0,0 +1,11 @@
+#include "libunwind_i.h"
+
+//! Set a alternative function to use in place of dl_iterate_phdr.
+/*! Suggested use is to specify an async-signal safe implementation.
+ *  If not set (or set to NULL) a the system dl_iterate_phdr will
+ *  be used. */
+PROTECTED void
+unw_set_iterate_phdr_function (unw_addr_space_t as, unw_iterate_phdr_func_t function)
+{
+    as->iterate_phdr_function = function;
+}
Index: src/mi/Lset_iterate_phdr_function.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/mi/Lset_iterate_phdr_function.c	2014-05-13 16:30:36.017906372 +0100
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
+#include "Gset_iterate_phdr_function.c"
+#endif
Index: src/mips/Ginit.c
===================================================================
--- src/mips/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/mips/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -196,6 +196,7 @@
 #endif
   local_addr_space.addr_size = sizeof (void *);
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/ppc32/Ginit.c
===================================================================
--- src/ppc32/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/ppc32/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -202,6 +202,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/ppc64/Ginit.c
===================================================================
--- src/ppc64/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/ppc64/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -217,6 +217,7 @@
   local_addr_space.abi = UNW_PPC64_ABI_ELFv1;
 #endif
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/sh/Ginit.c
===================================================================
--- src/sh/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/sh/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -172,6 +172,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/x86/Ginit.c
===================================================================
--- src/x86/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/x86/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -229,6 +229,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
Index: src/x86_64/Ginit.c
===================================================================
--- src/x86_64/Ginit.c.orig	2014-05-13 16:30:36.017906372 +0100
+++ src/x86_64/Ginit.c	2014-05-13 16:30:36.017906372 +0100
@@ -252,6 +252,7 @@
 {
   memset (&local_addr_space, 0, sizeof (local_addr_space));
   local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
+  local_addr_space.iterate_phdr_function = NULL;
   local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
   local_addr_space.acc.put_unwind_info = put_unwind_info;
   local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
_______________________________________________
Libunwind-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/libunwind-devel

Reply via email to