blob: 5e9069023d176d46a060b6c9fff6b681b3b35c2f [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 {
92 if (unw_get_proc_name (&cursor, name, sizeof (name), &off) == 0)
93 {
94 if (off)
95 snprintf (buf, sizeof (buf), "<%s+0x%lx>", name, (long) off);
96 else
97 {
98 size_t len = strlen (name);
99 buf[0] = '<';
100 memcpy (buf + 1, name, len);
101 buf[len + 1] = '>';
102 buf[len + 2] = '\0';
103 }
104 }
105 }
106
107 if (may_print && verbose)
108 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
109
110 ret = unw_step (&cursor);
111 if (ret < 0)
112 {
113 unw_get_reg (&cursor, UNW_REG_IP, &ip);
114 panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
115 ret, (long) ip);
116 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600117 if (depth++ > 100)
118 {
119 panic ("FAILURE: unw_step() looping over %d iterations\n", depth);
120 break;
121 }
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000122 }
123 while (ret > 0);
Paul Pluzhnikovb7e34442009-09-25 14:17:35 -0700124
125#ifndef CONFIG_BLOCK_SIGNALS
126 recurcount -= 1;
127#endif
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000128}
129
130void
131sighandler (int signal)
132{
133 if (verbose)
134 printf ("sighandler(signal=%d, count=%d)\n", signal, sigcount);
135
136 do_backtrace (1, 1);
137
138 ++sigcount;
139
140 if (sigcount == 100)
141 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_GLOBAL);
142 else if (sigcount == 200)
143 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_PER_THREAD);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600144 else if (sigcount == 300 || nerrors > nerrors_max)
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000145 {
Jan Kratochvila72abd42007-05-16 13:16:31 -0600146 if (nerrors > nerrors_max)
147 panic ("Too many errors (%d)\n", nerrors);
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000148 if (nerrors)
149 {
150 fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
151 exit (-1);
152 }
153 if (verbose)
154 printf ("SUCCESS.\n");
155 exit (0);
156 }
157 setitimer (ITIMER_VIRTUAL, &interval, NULL);
158}
159
160int
161main (int argc, char **argv)
162{
163 struct sigaction act;
164 long i = 0;
165
166 if (argc > 1)
167 verbose = 1;
168
169 unw_set_caching_policy (unw_local_addr_space, UNW_CACHE_NONE);
170
171 memset (&act, 0, sizeof (act));
172 act.sa_handler = sighandler;
173 act.sa_flags = SA_SIGINFO;
174 sigaction (SIGVTALRM, &act, NULL);
175
176 setitimer (ITIMER_VIRTUAL, &interval, NULL);
177
178 while (1)
179 {
180 if (0 && verbose)
181 printf ("%s: starting backtrace\n", __FUNCTION__);
182 do_backtrace (0, (i++ % 100) == 0);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600183 if (nerrors > nerrors_max)
184 {
185 panic ("Too many errors (%d)\n", nerrors);
186 exit (-1);
187 }
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000188 }
Konstantin Belousov459b2a52010-04-04 17:09:33 +0300189 return (0);
mostang.com!davidm4471c1e2004-04-01 08:11:21 +0000190}