blob: 9a0d39e6484226ed1fbbe8d245a2956da50bc088 [file] [log] [blame]
mostang.com!davidm4471c1e2004-04-01 08:11:21 +00001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2004 Hewlett-Packard Co
3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be
14included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23
24/* Check whether basic unwinding truly is async-signal safe. */
25
Konstantin Belousov459b2a52010-04-04 17:09:33 +030026#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <signal.h>
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000031#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36#include <sys/time.h>
37
38#define UNW_LOCAL_ONLY
39#include <libunwind.h>
40
David Mosberger-Tang5f3d2952007-05-16 13:19:46 -060041static const int nerrors_max = 100;
42
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000043struct itimerval interval =
44 {
45 .it_interval = { .tv_sec = 0, .tv_usec = 0 },
46 .it_value = { .tv_sec = 0, .tv_usec = 1000 }
47 };
48
49int verbose;
50int nerrors;
51int sigcount;
52
Paul Pluzhnikovb7e34442009-09-25 14:17:35 -070053#ifndef CONFIG_BLOCK_SIGNALS
54/* When libunwind is configured with --enable-block-signals=no, the caller
55 is responsible for preventing recursion via signal handlers.
56 We use a simple global here. In a multithreaded program, one would use
57 a thread-local variable. */
58int recurcount;
59#endif
60
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000061#define panic(args...) \
62 { ++nerrors; fprintf (stderr, args); return; }
63
64static void
65do_backtrace (int may_print, int get_proc_name)
66{
67 char buf[512], name[256];
68 unw_cursor_t cursor;
69 unw_word_t ip, sp, off;
70 unw_context_t uc;
71 int ret;
Jan Kratochvila72abd42007-05-16 13:16:31 -060072 int depth = 0;
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000073
Paul Pluzhnikovb7e34442009-09-25 14:17:35 -070074#ifndef CONFIG_BLOCK_SIGNALS
75 if (recurcount > 0)
76 return;
77 recurcount += 1;
78#endif
79
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000080 unw_getcontext (&uc);
81 if (unw_init_local (&cursor, &uc) < 0)
82 panic ("unw_init_local failed!\n");
83
84 do
85 {
86 unw_get_reg (&cursor, UNW_REG_IP, &ip);
87 unw_get_reg (&cursor, UNW_REG_SP, &sp);
88
89 buf[0] = '\0';
90 if (get_proc_name || (may_print && verbose))
91 {
Tommi Rantala848ad532012-08-16 10:25:56 +030092 ret = unw_get_proc_name (&cursor, name, sizeof (name), &off);
93 if (ret == 0 && (may_print && verbose))
mostang.com!davidm4471c1e2004-04-01 08:11:21 +000094 {
95 if (off)
96 snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off);
97 else
98 {
99 size_t len = strlen (name);
100 buf[0] = '<';
101 memcpy (buf + 1, name, len);
102 buf[len + 1] = '>';
103 buf[len + 2] = '\0';
104 }
105 }
106 }
107
108 if (may_print && verbose)
109 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
110
111 ret = unw_step (&cursor);
112 if (ret < 0)
113 {
114 unw_get_reg (&cursor, UNW_REG_IP, &ip);
115 panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
116 ret, (long) ip);
117 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600118 if (depth++ > 100)
119 {
120 panic ("FAILURE: unw_step() looping over %d iterations\n", depth);
121 break;
122 }
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000123 }
124 while (ret > 0);
Paul Pluzhnikovb7e34442009-09-25 14:17:35 -0700125
126#ifndef CONFIG_BLOCK_SIGNALS
127 recurcount -= 1;
128#endif
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000129}
130
131void
132sighandler (int signal)
133{
134 if (verbose)
135 printf ("sighandler(signal=%d, count=%d)\n", signal, sigcount);
136
137 do_backtrace (1, 1);
138
139 ++sigcount;
140
141 if (sigcount == 100)
142 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL);
143 else if (sigcount == 200)
144 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600145 else if (sigcount == 300 || nerrors > nerrors_max)
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000146 {
Jan Kratochvila72abd42007-05-16 13:16:31 -0600147 if (nerrors > nerrors_max)
148 panic ("Too many errors (%d)\n", nerrors);
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000149 if (nerrors)
150 {
151 fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
152 exit (-1);
153 }
154 if (verbose)
155 printf ("SUCCESS.\n");
156 exit (0);
157 }
158 setitimer (ITIMER_VIRTUAL, &interval, NULL);
159}
160
161int
Tommi Rantalaf42a8de2012-08-02 09:42:21 +0300162main (int argc, char **argv __attribute__((unused)))
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000163{
164 struct sigaction act;
165 long i = 0;
166
167 if (argc > 1)
168 verbose = 1;
169
170 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
171
172 memset (&act, 0, sizeof (act));
173 act.sa_handler = sighandler;
174 act.sa_flags = SA_SIGINFO;
175 sigaction (SIGVTALRM, &act, NULL);
176
177 setitimer (ITIMER_VIRTUAL, &interval, NULL);
178
179 while (1)
180 {
181 if (0 && verbose)
182 printf ("%s: starting backtrace\n", __FUNCTION__);
183 do_backtrace (0, (i++ % 100) == 0);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600184 if (nerrors > nerrors_max)
185 {
Tommi Rantala9a6d9212012-08-03 16:40:27 +0300186 fprintf (stderr, "Too many errors (%d)\n", nerrors);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600187 exit (-1);
188 }
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000189 }
Konstantin Belousov459b2a52010-04-04 17:09:33 +0300190 return (0);
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000191}