summary refs log tree commit diff
path: root/sysdeps/generic
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2021-03-01 15:56:36 +0100
committerFlorian Weimer <fweimer@redhat.com>2021-03-01 15:58:01 +0100
commit9fc813e1a37d2e2d5e85a97d5ac4fc1c15d839fb (patch)
tree62e5002b97acab6f776476c2325a37097693b0ea /sysdeps/generic
parent764e9a0334350f52ab6953bef1db97f9b2e89ca5 (diff)
downloadglibc-9fc813e1a37d2e2d5e85a97d5ac4fc1c15d839fb.tar.gz
glibc-9fc813e1a37d2e2d5e85a97d5ac4fc1c15d839fb.tar.xz
glibc-9fc813e1a37d2e2d5e85a97d5ac4fc1c15d839fb.zip
Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
This will be used to consolidate the libgcc_s access for backtrace
and pthread_cancel.

Unlike the existing backtrace implementations, it provides some
hardening based on pointer mangling.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'sysdeps/generic')
-rw-r--r--sysdeps/generic/unwind-arch.h27
-rw-r--r--sysdeps/generic/unwind-link.h106
2 files changed, 122 insertions, 11 deletions
diff --git a/sysdeps/generic/unwind-arch.h b/sysdeps/generic/unwind-arch.h
index feda585e8d..ead6674279 100644
--- a/sysdeps/generic/unwind-arch.h
+++ b/sysdeps/generic/unwind-arch.h
@@ -1,5 +1,5 @@
-/* Return backtrace of current program state.  Arch-specific bits.
-   Copyright (C) 2020-2021 Free Software Foundation, Inc.
+/* Dynamic loading of the libgcc unwinder.  Generic version of parameters.
+   Copyright (C) 2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,15 +16,20 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#ifndef _UNWIND_ARCH_H
-#define _UNWIND_ARCH_H
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
 
-#include <unwind.h>
+/* The _Unwind_GetIP function is supported.  */
+#define UNWIND_LINK_GETIP 1
 
-static inline void *
-unwind_arch_adjustment (void *prev, void *addr)
-{
-  return addr;
-}
+/* The __frame_state_for function is needed and re-exported from glibc.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
 
-#endif
+/* No adjustment of the is needed.  */
+#define UNWIND_LINK_FRAME_ADJUSTMENT 0
+
+/* There are no extra fields in struct unwind_link in the generic version.  */
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/generic/unwind-link.h b/sysdeps/generic/unwind-link.h
new file mode 100644
index 0000000000..3527cebe2d
--- /dev/null
+++ b/sysdeps/generic/unwind-link.h
@@ -0,0 +1,106 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+#define _UNWIND_LINK_H
+
+#include <unwind.h>
+#include <unwind-arch.h>
+
+#if !UNWIND_LINK_FRAME_ADJUSTMENT
+static inline void *
+unwind_arch_adjustment (void *prev, void *addr)
+{
+  return addr;
+}
+#endif
+
+#ifdef SHARED
+# include <sysdep.h>
+# include <unwind-resume.h>
+
+# if UNWIND_LINK_FRAME_STATE_FOR
+struct frame_state;
+# endif
+
+struct unwind_link
+{
+  __typeof (_Unwind_Backtrace) *ptr__Unwind_Backtrace;
+  __typeof (_Unwind_ForcedUnwind) *ptr__Unwind_ForcedUnwind;
+  __typeof (_Unwind_GetCFA) *ptr__Unwind_GetCFA;
+# if UNWIND_LINK_GETIP
+  __typeof (_Unwind_GetIP) *ptr__Unwind_GetIP;
+# endif
+  __typeof (_Unwind_Resume) *ptr__Unwind_Resume;
+#if UNWIND_LINK_FRAME_STATE_FOR
+  struct frame_state *(*ptr___frame_state_for) (void *, struct frame_state *);
+#endif
+  _Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
+  UNWIND_LINK_EXTRA_FIELDS
+};
+
+/* Return a pointer to the implementation, or NULL on failure.  */
+struct unwind_link *__libc_unwind_link_get (void);
+libc_hidden_proto (__libc_unwind_link_get)
+
+/* UNWIND_LINK_PTR returns the stored function pointer NAME from the
+   cached unwind link OBJ (which was previously returned by
+   __libc_unwind_link_get).  */
+# ifdef PTR_DEMANGLE
+#  define UNWIND_LINK_PTR(obj, name, ...)                          \
+  ({                                                                \
+    __typeof ((obj)->ptr_##name) __unwind_fptr = (obj)->ptr_##name; \
+    PTR_DEMANGLE (__unwind_fptr);                                   \
+    __unwind_fptr;                                                  \
+  })
+# else /* !PTR_DEMANGLE */
+#  define UNWIND_LINK_PTR(obj, name, ...) ((obj)->ptr_##name)
+# endif
+
+/* Called from fork, in the new subprocess.  */
+void __libc_unwind_link_after_fork (void);
+
+/* Called from __libc_freeres.  */
+void __libc_unwind_link_freeres (void) attribute_hidden;
+
+#else /* !SHARED */
+
+/* Dummy implementation so that the code can be shared with the SHARED
+   version.  */
+struct unwind_link;
+static inline struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Return something that is not a null pointer, so that error checks
+     succeed.  */
+  return (struct unwind_link *) 1;
+}
+
+/* Directly call the static implementation.  */
+# define UNWIND_LINK_PTR(obj, name, ...) \
+  ((void) (obj), &name)
+
+static inline void
+__libc_unwind_link_after_fork (void)
+{
+  /* No need to clean up if the unwinder is statically linked.  */
+}
+
+#endif /* !SHARED */
+
+#endif /* _UNWIND_LINK_H */