unwind-link.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* Dynamic loading of the libgcc unwinder.
  2. Copyright (C) 2021-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef SHARED
  16. #include <assert.h>
  17. #include <dlfcn.h>
  18. #include <gnu/lib-names.h>
  19. #include <unwind-link.h>
  20. #include <libc-lock.h>
  21. #include <pointer_guard.h>
  22. /* Statically allocate the object, so that we do not have to deal with
  23. malloc failure. __libc_unwind_link_get must not fail if libgcc_s
  24. has already been loaded by other means. */
  25. static struct unwind_link global;
  26. /* dlopen handle. Also used for the double-checked locking idiom. */
  27. static void *global_libgcc_handle;
  28. /* We cannot use __libc_once because the pthread_once implementation
  29. may depend on unwinding. */
  30. __libc_lock_define (static, lock);
  31. struct unwind_link *
  32. __libc_unwind_link_get (void)
  33. {
  34. /* Double-checked locking idiom. Synchronizes with the release MO
  35. store at the end of this function. */
  36. if (atomic_load_acquire (&global_libgcc_handle) != NULL)
  37. return &global;
  38. /* Initialize a copy of the data, so that we do not need about
  39. unlocking in case the dynamic loader somehow triggers
  40. unwinding. */
  41. void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
  42. if (local_libgcc_handle == NULL)
  43. {
  44. __libc_lock_unlock (lock);
  45. return NULL;
  46. }
  47. struct unwind_link local;
  48. local.ptr__Unwind_Backtrace
  49. = __libc_dlsym (local_libgcc_handle, "_Unwind_Backtrace");
  50. local.ptr__Unwind_ForcedUnwind
  51. = __libc_dlsym (local_libgcc_handle, "_Unwind_ForcedUnwind");
  52. local.ptr__Unwind_GetCFA
  53. = __libc_dlsym (local_libgcc_handle, "_Unwind_GetCFA");
  54. #if UNWIND_LINK_GETIP
  55. local.ptr__Unwind_GetIP
  56. = __libc_dlsym (local_libgcc_handle, "_Unwind_GetIP");
  57. #endif
  58. local.ptr__Unwind_Resume
  59. = __libc_dlsym (local_libgcc_handle, "_Unwind_Resume");
  60. #if UNWIND_LINK_FRAME_STATE_FOR
  61. local.ptr___frame_state_for
  62. = __libc_dlsym (local_libgcc_handle, "__frame_state_for");
  63. #endif
  64. local.ptr_personality
  65. = __libc_dlsym (local_libgcc_handle, "__gcc_personality_v0");
  66. UNWIND_LINK_EXTRA_INIT
  67. /* If a symbol is missing, libgcc_s has somehow been corrupted. */
  68. assert (local.ptr__Unwind_Backtrace != NULL);
  69. assert (local.ptr__Unwind_ForcedUnwind != NULL);
  70. assert (local.ptr__Unwind_GetCFA != NULL);
  71. #if UNWIND_LINK_GETIP
  72. assert (local.ptr__Unwind_GetIP != NULL);
  73. #endif
  74. assert (local.ptr__Unwind_Resume != NULL);
  75. assert (local.ptr_personality != NULL);
  76. PTR_MANGLE (local.ptr__Unwind_Backtrace);
  77. PTR_MANGLE (local.ptr__Unwind_ForcedUnwind);
  78. PTR_MANGLE (local.ptr__Unwind_GetCFA);
  79. #if UNWIND_LINK_GETIP
  80. PTR_MANGLE (local.ptr__Unwind_GetIP);
  81. #endif
  82. PTR_MANGLE (local.ptr__Unwind_Resume);
  83. #if UNWIND_LINK_FRAME_STATE_FOR
  84. PTR_MANGLE (local.ptr___frame_state_for);
  85. #endif
  86. PTR_MANGLE (local.ptr_personality);
  87. __libc_lock_lock (lock);
  88. if (atomic_load_relaxed (&global_libgcc_handle) != NULL)
  89. /* This thread lost the race. Clean up. */
  90. __libc_dlclose (local_libgcc_handle);
  91. else
  92. {
  93. global = local;
  94. /* Completes the double-checked locking idiom. */
  95. atomic_store_release (&global_libgcc_handle, local_libgcc_handle);
  96. }
  97. __libc_lock_unlock (lock);
  98. return &global;
  99. }
  100. libc_hidden_def (__libc_unwind_link_get)
  101. void
  102. __libc_unwind_link_after_fork (void)
  103. {
  104. if (__libc_lock_trylock (lock) == 0)
  105. /* The lock was not acquired during the fork. This covers both
  106. the initialized and uninitialized case. */
  107. __libc_lock_unlock (lock);
  108. else
  109. {
  110. /* Initialization was in progress in another thread.
  111. Reinitialize the lock. */
  112. __libc_lock_init (lock);
  113. global_libgcc_handle = NULL;
  114. }
  115. }
  116. void
  117. __libc_unwind_link_freeres (void)
  118. {
  119. if (global_libgcc_handle != NULL)
  120. {
  121. __libc_dlclose (global_libgcc_handle );
  122. global_libgcc_handle = NULL;
  123. }
  124. }
  125. #endif /* SHARED */