blob: 11fffee49d655ee7d54f6730af6381a051a323a2 [file] [log] [blame]
hp.com!davidme9e4e5f2003-01-28 03:40:06 +00001/* libunwind - a platform-independent unwind library
mostang.com!davidma4bd80c2004-04-21 07:24:35 +00002 Copyright (C) 2003-2004 Hewlett-Packard Co
hp.com!davidme9e4e5f2003-01-28 03:40:06 +00003 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
mostang.com!davidmba424722004-05-04 22:19:18 +000026#include <config.h>
27
28#ifdef HAVE_TTRACE
29
30int
31main (int argc, char **argv)
32{
33 printf ("FAILURE: ttrace() not supported yet\n");
34 return -1;
35}
36
37#else /* !HAVE_TTRACE */
38
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000039#include <errno.h>
40#include <fcntl.h>
mostang.com!davidm40a15582004-01-21 01:05:07 +000041#include <libunwind-ptrace.h>
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000042#include <stdio.h>
43#include <stdlib.h>
hp.com!davidmb97fa142003-02-26 08:33:57 +000044#include <string.h>
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000045#include <unistd.h>
46
47#include <sys/ptrace.h>
48#include <sys/wait.h>
49
50int nerrors;
Jan Kratochvila72abd42007-05-16 13:16:31 -060051static const int nerrors_max = 100;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000052int verbose;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000053int print_names = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000054
hp.com!davidmb97fa142003-02-26 08:33:57 +000055enum
56 {
57 INSTRUCTION,
58 SYSCALL,
59 TRIGGER
60 }
61trace_mode = SYSCALL;
62
hp.com!davidmb0048ee2004-10-15 13:48:38 +000063#define panic(args...) \
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000064 do { fprintf (stderr, args); ++nerrors; } while (0)
65
66static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000067static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000068
Jan Kratochvila72abd42007-05-16 13:16:31 -060069static int killed;
70
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000071void
72do_backtrace (pid_t target_pid)
73{
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000074 unw_word_t ip, sp, start_ip = 0, off;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000075 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000076 unw_proc_info_t pi;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077 unw_cursor_t c;
78 char buf[512];
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000079 size_t len;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000080
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000081 ret = unw_init_remote (&c, as, ui);
82 if (ret < 0)
83 panic ("unw_init_remote() failed: ret=%d\n", ret);
84
85 do
86 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000087 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
88 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
89 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
90
hp.com!davidmb0048ee2004-10-15 13:48:38 +000091 if (n == 0)
92 start_ip = ip;
93
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000094 buf[0] = '\0';
95 if (print_names)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000096 unw_get_proc_name (&c, buf, sizeof (buf), &off);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000097
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000098 if (verbose)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000099 {
100 if (off)
101 {
102 len = strlen (buf);
103 if (len >= sizeof (buf) - 32)
104 len = sizeof (buf) - 32;
Jan Kratochvila72abd42007-05-16 13:16:31 -0600105 sprintf (buf + len, "+0x%lx", (unsigned long) off);
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000106 }
107 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
108 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000109
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000110 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000111 panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000112 else if (verbose)
113 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
114 (long) pi.start_ip, (long) pi.end_ip,
115 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000116
117#if UNW_TARGET_IA64
118 {
119 unw_word_t bsp;
120
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000121 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
122 panic ("unw_get_reg() failed: ret=%d\n", ret);
123 else if (verbose)
124 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000125 }
126#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000127 if (verbose)
128 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000129
130 ret = unw_step (&c);
131 if (ret < 0)
132 {
133 unw_get_reg (&c, UNW_REG_IP, &ip);
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000134 panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n",
135 ret, (long) ip, (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000136 }
137
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000138 if (++n > 64)
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000139 {
140 /* guard against bad unwind info in old libraries... */
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000141 panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n",
142 (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000143 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000144 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600145 if (nerrors > nerrors_max)
146 {
147 panic ("Too many errors (%d)!\n", nerrors);
148 break;
149 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000150 }
151 while (ret > 0);
152
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000153 if (ret < 0)
154 panic ("unwind failed with ret=%d\n", ret);
155
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000156 if (verbose)
157 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000158}
159
Jan Kratochvila72abd42007-05-16 13:16:31 -0600160static pid_t target_pid;
161static void target_pid_kill (void)
162{
163 kill (target_pid, SIGKILL);
164}
165
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000166int
167main (int argc, char **argv)
168{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000169 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000170
171 as = unw_create_addr_space (&_UPT_accessors, 0);
172 if (!as)
173 panic ("unw_create_addr_space() failed");
174
175 if (argc == 1)
176 {
177 char *args[] = { "self", "/bin/ls", "/usr", NULL };
178
179 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000180 argv = args;
181 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000182 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000183 while (argv[optind][0] == '-')
184 {
185 if (strcmp (argv[optind], "-v") == 0)
186 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000187 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000188 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
189 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000190 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000191 else if (strcmp (argv[optind], "-t") == 0)
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000192 /* Execute until raise(SIGUSR1), then backtrace at each insn
193 until raise(SIGUSR2). */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000194 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000195 else if (strcmp (argv[optind], "-c") == 0)
196 /* Enable caching of unwind-info. */
197 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
198 else if (strcmp (argv[optind], "-n") == 0)
199 /* Don't look-up and print symbol names. */
200 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000201 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000202
203 target_pid = fork ();
204 if (!target_pid)
205 {
206 /* child */
207
208 if (!verbose)
209 dup2 (open ("/dev/null", O_WRONLY), 1);
210
211 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000212 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000213 _exit (-1);
214 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600215 atexit (target_pid_kill);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000216
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000217 ui = _UPT_create (target_pid);
218
Jan Kratochvila72abd42007-05-16 13:16:31 -0600219 while (nerrors <= nerrors_max)
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000220 {
221 pid = wait4 (-1, &status, 0, 0);
222 if (pid == -1)
223 {
224 if (errno == EINTR)
225 continue;
226
227 panic ("wait4() failed (errno=%d)\n", errno);
228 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000229 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000230 if (WIFSIGNALED (status) || WIFEXITED (status)
231 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
232 {
233 if (WIFEXITED (status))
234 {
235 if (WEXITSTATUS (status) != 0)
236 panic ("child's exit status %d\n", WEXITSTATUS (status));
237 break;
238 }
239 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000240 {
Jan Kratochvila72abd42007-05-16 13:16:31 -0600241 if (!killed)
242 panic ("child terminated by signal %d\n", WTERMSIG (status));
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000243 break;
244 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000245 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000246 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000247 pending_sig = WSTOPSIG (status);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600248 /* Avoid deadlock: */
249 if (WSTOPSIG (status) == SIGKILL)
250 break;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000251 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000252 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000253 if (WSTOPSIG (status) == SIGUSR1)
254 state = 0;
255 else if (WSTOPSIG (status) == SIGUSR2)
256 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000257 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600258 if (WSTOPSIG (status) != SIGUSR1 && WSTOPSIG (status) != SIGUSR2)
259 {
260 static int count = 0;
261
262 if (count++ > 100)
263 {
264 panic ("Too many child unexpected signals (now %d)\n",
265 WSTOPSIG (status));
266 killed = 1;
267 }
268 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000269 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000270 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000271
272 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000273 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000274 case TRIGGER:
275 if (state)
276 ptrace (PTRACE_CONT, target_pid, 0, 0);
277 else
278 {
279 do_backtrace (target_pid);
280 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
281 }
282 break;
283
284 case SYSCALL:
285 if (!state)
286 do_backtrace (target_pid);
287 state ^= 1;
288 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
289 break;
290
291 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000292 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000293 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
294 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000295 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600296 if (killed)
297 kill (target_pid, SIGKILL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000298 }
299
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000300 _UPT_destroy (ui);
301
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000302 if (nerrors)
303 {
304 printf ("FAILURE: detected %d errors\n", nerrors);
305 exit (-1);
306 }
307 if (verbose)
308 printf ("SUCCESS\n");
309
310 return 0;
311}
mostang.com!davidmba424722004-05-04 22:19:18 +0000312
313#endif /* !HAVE_TTRACE */