blob: 2bbbee20d51b10515b00739669cd09dc28c048a8 [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;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000051int verbose;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000052int print_names = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000053
hp.com!davidmb97fa142003-02-26 08:33:57 +000054enum
55 {
56 INSTRUCTION,
57 SYSCALL,
58 TRIGGER
59 }
60trace_mode = SYSCALL;
61
hp.com!davidmb0048ee2004-10-15 13:48:38 +000062#define panic(args...) \
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000063 do { fprintf (stderr, args); ++nerrors; } while (0)
64
65static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000066static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000067
68void
69do_backtrace (pid_t target_pid)
70{
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000071 unw_word_t ip, sp, start_ip = 0, off;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000072 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000073 unw_proc_info_t pi;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000074 unw_cursor_t c;
75 char buf[512];
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000076 size_t len;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000078 ret = unw_init_remote (&c, as, ui);
79 if (ret < 0)
80 panic ("unw_init_remote() failed: ret=%d\n", ret);
81
82 do
83 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000084 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
85 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
86 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
87
hp.com!davidmb0048ee2004-10-15 13:48:38 +000088 if (n == 0)
89 start_ip = ip;
90
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000091 buf[0] = '\0';
92 if (print_names)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000093 unw_get_proc_name (&c, buf, sizeof (buf), &off);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000094
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000095 if (verbose)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +000096 {
97 if (off)
98 {
99 len = strlen (buf);
100 if (len >= sizeof (buf) - 32)
101 len = sizeof (buf) - 32;
102 sprintf (buf + len, "+0x%lx", off);
103 }
104 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
105 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000106
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000107 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000108 panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip, ret);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000109 else if (verbose)
110 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
111 (long) pi.start_ip, (long) pi.end_ip,
112 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000113
114#if UNW_TARGET_IA64
115 {
116 unw_word_t bsp;
117
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000118 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
119 panic ("unw_get_reg() failed: ret=%d\n", ret);
120 else if (verbose)
121 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000122 }
123#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000124 if (verbose)
125 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000126
127 ret = unw_step (&c);
128 if (ret < 0)
129 {
130 unw_get_reg (&c, UNW_REG_IP, &ip);
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000131 panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n",
132 ret, (long) ip, (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000133 }
134
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000135 if (++n > 64)
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000136 {
137 /* guard against bad unwind info in old libraries... */
hp.com!davidm95c9a4a2005-05-03 09:13:17 +0000138 panic ("too deeply nested---assuming bogus unwind (start ip=%lx)\n",
139 (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000140 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000141 }
142 }
143 while (ret > 0);
144
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000145 if (ret < 0)
146 panic ("unwind failed with ret=%d\n", ret);
147
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000148 if (verbose)
149 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000150}
151
152int
153main (int argc, char **argv)
154{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000155 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000156 pid_t target_pid;
157
158 as = unw_create_addr_space (&_UPT_accessors, 0);
159 if (!as)
160 panic ("unw_create_addr_space() failed");
161
162 if (argc == 1)
163 {
164 char *args[] = { "self", "/bin/ls", "/usr", NULL };
165
166 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000167 argv = args;
168 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000169 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000170 while (argv[optind][0] == '-')
171 {
172 if (strcmp (argv[optind], "-v") == 0)
173 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000174 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000175 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
176 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000177 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000178 else if (strcmp (argv[optind], "-t") == 0)
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000179 /* Execute until raise(SIGUSR1), then backtrace at each insn
180 until raise(SIGUSR2). */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000181 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000182 else if (strcmp (argv[optind], "-c") == 0)
183 /* Enable caching of unwind-info. */
184 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
185 else if (strcmp (argv[optind], "-n") == 0)
186 /* Don't look-up and print symbol names. */
187 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000188 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000189
190 target_pid = fork ();
191 if (!target_pid)
192 {
193 /* child */
194
195 if (!verbose)
196 dup2 (open ("/dev/null", O_WRONLY), 1);
197
198 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000199 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000200 _exit (-1);
201 }
202
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000203 ui = _UPT_create (target_pid);
204
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000205 while (1)
206 {
207 pid = wait4 (-1, &status, 0, 0);
208 if (pid == -1)
209 {
210 if (errno == EINTR)
211 continue;
212
213 panic ("wait4() failed (errno=%d)\n", errno);
214 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000215 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000216 if (WIFSIGNALED (status) || WIFEXITED (status)
217 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
218 {
219 if (WIFEXITED (status))
220 {
221 if (WEXITSTATUS (status) != 0)
222 panic ("child's exit status %d\n", WEXITSTATUS (status));
223 break;
224 }
225 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000226 {
227 panic ("child terminated by signal %d\n", WTERMSIG (status));
228 break;
229 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000230 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000231 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000232 pending_sig = WSTOPSIG (status);
233 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000234 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000235 if (WSTOPSIG (status) == SIGUSR1)
236 state = 0;
237 else if (WSTOPSIG (status) == SIGUSR2)
238 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000239 }
240 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000241 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000242
243 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000244 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000245 case TRIGGER:
246 if (state)
247 ptrace (PTRACE_CONT, target_pid, 0, 0);
248 else
249 {
250 do_backtrace (target_pid);
251 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
252 }
253 break;
254
255 case SYSCALL:
256 if (!state)
257 do_backtrace (target_pid);
258 state ^= 1;
259 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
260 break;
261
262 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000263 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000264 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
265 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000266 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000267 }
268
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000269 _UPT_destroy (ui);
270
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000271 if (nerrors)
272 {
273 printf ("FAILURE: detected %d errors\n", nerrors);
274 exit (-1);
275 }
276 if (verbose)
277 printf ("SUCCESS\n");
278
279 return 0;
280}
mostang.com!davidmba424722004-05-04 22:19:18 +0000281
282#endif /* !HAVE_TTRACE */