blob: 1f46f7d81243fd24fbd89cae36a0a7a20bef4813 [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
Jan Kratochvila72abd42007-05-16 13:16:31 -060050static const int nerrors_max = 100;
David Mosberger-Tang5f3d2952007-05-16 13:19:46 -060051
52int nerrors;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000053int verbose;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000054int print_names = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000055
hp.com!davidmb97fa142003-02-26 08:33:57 +000056enum
57 {
58 INSTRUCTION,
59 SYSCALL,
60 TRIGGER
61 }
62trace_mode = SYSCALL;
63
hp.com!davidmb0048ee2004-10-15 13:48:38 +000064#define panic(args...) \
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000065 do { fprintf (stderr, args); ++nerrors; } while (0)
66
67static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000068static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000069
Jan Kratochvila72abd42007-05-16 13:16:31 -060070static int killed;
71
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000072void
73do_backtrace (pid_t target_pid)
74{
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000075 unw_word_t ip, sp, start_ip = 0, off;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000076 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077 unw_proc_info_t pi;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000078 unw_cursor_t c;
79 char buf[512];
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000080 size_t len;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000081
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000082 ret = unw_init_remote (&c, as, ui);
83 if (ret < 0)
84 panic ("unw_init_remote() failed: ret=%d\n", ret);
85
86 do
87 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000088 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
89 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
90 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
91
hp.com!davidmb0048ee2004-10-15 13:48:38 +000092 if (n == 0)
93 start_ip = ip;
94
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000095 buf[0] = '\0';
96 if (print_names)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000097 unw_get_proc_name (&c, buf, sizeof (buf), &off);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000098
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000099 if (verbose)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000100 {
101 if (off)
102 {
103 len = strlen (buf);
104 if (len >= sizeof (buf) - 32)
105 len = sizeof (buf) - 32;
Jan Kratochvila72abd42007-05-16 13:16:31 -0600106 sprintf (buf + len, "+0x%lx", (unsigned long) off);
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000107 }
108 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
109 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000110
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000111 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000112 panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000113 else if (verbose)
114 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
115 (long) pi.start_ip, (long) pi.end_ip,
116 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000117
118#if UNW_TARGET_IA64
119 {
120 unw_word_t bsp;
121
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000122 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
123 panic ("unw_get_reg() failed: ret=%d\n", ret);
124 else if (verbose)
125 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000126 }
127#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000128 if (verbose)
129 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000130
131 ret = unw_step (&c);
132 if (ret < 0)
133 {
134 unw_get_reg (&c, UNW_REG_IP, &ip);
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000135 panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n",
136 ret, (long) ip, (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000137 }
138
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000139 if (++n > 64)
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000140 {
141 /* guard against bad unwind info in old libraries... */
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000142 panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n",
143 (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000144 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000145 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600146 if (nerrors > nerrors_max)
147 {
148 panic ("Too many errors (%d)!\n", nerrors);
149 break;
150 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000151 }
152 while (ret > 0);
153
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000154 if (ret < 0)
155 panic ("unwind failed with ret=%d\n", ret);
156
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000157 if (verbose)
158 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000159}
160
Jan Kratochvila72abd42007-05-16 13:16:31 -0600161static pid_t target_pid;
162static void target_pid_kill (void)
163{
164 kill (target_pid, SIGKILL);
165}
166
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000167int
168main (int argc, char **argv)
169{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000170 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000171
172 as = unw_create_addr_space (&_UPT_accessors, 0);
173 if (!as)
174 panic ("unw_create_addr_space() failed");
175
176 if (argc == 1)
177 {
178 char *args[] = { "self", "/bin/ls", "/usr", NULL };
179
180 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000181 argv = args;
182 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000183 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000184 while (argv[optind][0] == '-')
185 {
186 if (strcmp (argv[optind], "-v") == 0)
187 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000188 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000189 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
190 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000191 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000192 else if (strcmp (argv[optind], "-t") == 0)
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000193 /* Execute until raise(SIGUSR1), then backtrace at each insn
194 until raise(SIGUSR2). */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000195 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000196 else if (strcmp (argv[optind], "-c") == 0)
197 /* Enable caching of unwind-info. */
198 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
199 else if (strcmp (argv[optind], "-n") == 0)
200 /* Don't look-up and print symbol names. */
201 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000202 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000203
204 target_pid = fork ();
205 if (!target_pid)
206 {
207 /* child */
208
209 if (!verbose)
210 dup2 (open ("/dev/null", O_WRONLY), 1);
211
212 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000213 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000214 _exit (-1);
215 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600216 atexit (target_pid_kill);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000217
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000218 ui = _UPT_create (target_pid);
219
Jan Kratochvila72abd42007-05-16 13:16:31 -0600220 while (nerrors <= nerrors_max)
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000221 {
222 pid = wait4 (-1, &status, 0, 0);
223 if (pid == -1)
224 {
225 if (errno == EINTR)
226 continue;
227
228 panic ("wait4() failed (errno=%d)\n", errno);
229 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000230 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000231 if (WIFSIGNALED (status) || WIFEXITED (status)
232 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
233 {
234 if (WIFEXITED (status))
235 {
236 if (WEXITSTATUS (status) != 0)
237 panic ("child's exit status %d\n", WEXITSTATUS (status));
238 break;
239 }
240 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000241 {
Jan Kratochvila72abd42007-05-16 13:16:31 -0600242 if (!killed)
243 panic ("child terminated by signal %d\n", WTERMSIG (status));
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000244 break;
245 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000246 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000247 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000248 pending_sig = WSTOPSIG (status);
Jan Kratochvila72abd42007-05-16 13:16:31 -0600249 /* Avoid deadlock: */
250 if (WSTOPSIG (status) == SIGKILL)
251 break;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000252 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000253 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000254 if (WSTOPSIG (status) == SIGUSR1)
255 state = 0;
256 else if (WSTOPSIG (status) == SIGUSR2)
257 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000258 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600259 if (WSTOPSIG (status) != SIGUSR1 && WSTOPSIG (status) != SIGUSR2)
260 {
261 static int count = 0;
262
263 if (count++ > 100)
264 {
265 panic ("Too many child unexpected signals (now %d)\n",
266 WSTOPSIG (status));
267 killed = 1;
268 }
269 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000270 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000271 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000272
273 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000274 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000275 case TRIGGER:
276 if (state)
277 ptrace (PTRACE_CONT, target_pid, 0, 0);
278 else
279 {
280 do_backtrace (target_pid);
281 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
282 }
283 break;
284
285 case SYSCALL:
286 if (!state)
287 do_backtrace (target_pid);
288 state ^= 1;
289 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
290 break;
291
292 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000293 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000294 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
295 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000296 }
Jan Kratochvila72abd42007-05-16 13:16:31 -0600297 if (killed)
298 kill (target_pid, SIGKILL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000299 }
300
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000301 _UPT_destroy (ui);
302
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000303 if (nerrors)
304 {
305 printf ("FAILURE: detected %d errors\n", nerrors);
306 exit (-1);
307 }
308 if (verbose)
309 printf ("SUCCESS\n");
310
311 return 0;
312}
mostang.com!davidmba424722004-05-04 22:19:18 +0000313
314#endif /* !HAVE_TTRACE */