Prefer https to http for gnu.org and fsf.org URLs
[platform/upstream/glibc.git] / sysdeps / arm / backtrace.c
1 /* Return backtrace of current program state.
2    Copyright (C) 2008-2019 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Kazu Hirata <kazu@codesourcery.com>, 2008.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library.  If not, see
18    <https://www.gnu.org/licenses/>.  */
19
20 #include <libc-lock.h>
21 #include <dlfcn.h>
22 #include <execinfo.h>
23 #include <stdlib.h>
24 #include <unwind.h>
25
26 struct trace_arg
27 {
28   void **array;
29   int cnt, size;
30 };
31
32 #ifdef SHARED
33 static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
34 static _Unwind_VRS_Result (*unwind_vrs_get) (_Unwind_Context *,
35                                              _Unwind_VRS_RegClass,
36                                              _uw,
37                                              _Unwind_VRS_DataRepresentation,
38                                              void *);
39
40 static void *libgcc_handle;
41
42 static void
43 init (void)
44 {
45   libgcc_handle = __libc_dlopen ("libgcc_s.so.1");
46
47   if (libgcc_handle == NULL)
48     return;
49
50   unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
51   unwind_vrs_get = __libc_dlsym (libgcc_handle, "_Unwind_VRS_Get");
52   if (unwind_vrs_get == NULL)
53     unwind_backtrace = NULL;
54 }
55
56 /* This function is identical to "_Unwind_GetGR", except that it uses
57    "unwind_vrs_get" instead of "_Unwind_VRS_Get".  */
58 static inline _Unwind_Word
59 unwind_getgr (_Unwind_Context *context, int regno)
60 {
61   _uw val;
62   unwind_vrs_get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
63   return val;
64 }
65
66 /* This macro is identical to the _Unwind_GetIP macro, except that it
67    uses "unwind_getgr" instead of "_Unwind_GetGR".  */
68 # define unwind_getip(context) \
69   (unwind_getgr (context, 15) & ~(_Unwind_Word)1)
70 #else
71 # define unwind_backtrace _Unwind_Backtrace
72 # define unwind_getip _Unwind_GetIP
73 #endif
74
75 static _Unwind_Reason_Code
76 backtrace_helper (struct _Unwind_Context *ctx, void *a)
77 {
78   struct trace_arg *arg = a;
79
80   /* We are first called with address in the __backtrace function.
81      Skip it.  */
82   if (arg->cnt != -1)
83     arg->array[arg->cnt] = (void *) unwind_getip (ctx);
84   if (++arg->cnt == arg->size)
85     return _URC_END_OF_STACK;
86   return _URC_NO_REASON;
87 }
88
89 int
90 __backtrace (void **array, int size)
91 {
92   struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
93
94   if (size <= 0)
95     return 0;
96
97 #ifdef SHARED
98   __libc_once_define (static, once);
99
100   __libc_once (once, init);
101   if (unwind_backtrace == NULL)
102     return 0;
103 #endif
104
105   unwind_backtrace (backtrace_helper, &arg);
106
107   if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
108     --arg.cnt;
109   return arg.cnt != -1 ? arg.cnt : 0;
110 }
111 weak_alias (__backtrace, backtrace)
112 libc_hidden_def (__backtrace)
113
114
115 #ifdef SHARED
116 /* Free all resources if necessary.  */
117 libc_freeres_fn (free_mem)
118 {
119   unwind_backtrace = NULL;
120   if (libgcc_handle != NULL)
121     {
122       __libc_dlclose (libgcc_handle);
123       libgcc_handle = NULL;
124     }
125 }
126 #endif