blob: 73409db833a9298565841468d92878a32db893af [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{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000071 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000072 unw_proc_info_t pi;
hp.com!davidmb0048ee2004-10-15 13:48:38 +000073 unw_word_t ip, sp, start_ip;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000074 unw_cursor_t c;
75 char buf[512];
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000076
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077 ret = unw_init_remote (&c, as, ui);
78 if (ret < 0)
79 panic ("unw_init_remote() failed: ret=%d\n", ret);
80
81 do
82 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000083 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
84 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
85 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
86
hp.com!davidmb0048ee2004-10-15 13:48:38 +000087 if (n == 0)
88 start_ip = ip;
89
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000090 buf[0] = '\0';
91 if (print_names)
92 unw_get_proc_name (&c, buf, sizeof (buf), NULL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000093
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000094 if (verbose)
95 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000096
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000097 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
98 panic ("unw_get_proc_info() failed: ret=%d\n", ret);
99 else if (verbose)
100 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
101 (long) pi.start_ip, (long) pi.end_ip,
102 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000103
104#if UNW_TARGET_IA64
105 {
106 unw_word_t bsp;
107
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000108 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
109 panic ("unw_get_reg() failed: ret=%d\n", ret);
110 else if (verbose)
111 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000112 }
113#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000114 if (verbose)
115 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000116
117 ret = unw_step (&c);
118 if (ret < 0)
119 {
120 unw_get_reg (&c, UNW_REG_IP, &ip);
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000121 panic ("FAILURE: unw_step() returned %d for ip=%lx (start ip=%lx)\n",
122 ret, (long) ip, (long) start_ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000123 }
124
125 if (++n > 32)
126 {
127 /* guard against bad unwind info in old libraries... */
128 panic ("too deeply nested---assuming bogus unwind\n");
129 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000130 }
131 }
132 while (ret > 0);
133
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000134 if (ret < 0)
135 panic ("unwind failed with ret=%d\n", ret);
136
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000137 if (verbose)
138 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000139}
140
141int
142main (int argc, char **argv)
143{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000144 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000145 pid_t target_pid;
146
147 as = unw_create_addr_space (&_UPT_accessors, 0);
148 if (!as)
149 panic ("unw_create_addr_space() failed");
150
151 if (argc == 1)
152 {
153 char *args[] = { "self", "/bin/ls", "/usr", NULL };
154
155 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000156 argv = args;
157 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000158 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000159 while (argv[optind][0] == '-')
160 {
161 if (strcmp (argv[optind], "-v") == 0)
162 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000163 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000164 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
165 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000166 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000167 else if (strcmp (argv[optind], "-t") == 0)
hp.com!davidmb0048ee2004-10-15 13:48:38 +0000168 /* Execute until raise(SIGUSR1), then backtrace at each insn
169 until raise(SIGUSR2). */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000170 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000171 else if (strcmp (argv[optind], "-c") == 0)
172 /* Enable caching of unwind-info. */
173 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
174 else if (strcmp (argv[optind], "-n") == 0)
175 /* Don't look-up and print symbol names. */
176 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000177 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000178
179 target_pid = fork ();
180 if (!target_pid)
181 {
182 /* child */
183
184 if (!verbose)
185 dup2 (open ("/dev/null", O_WRONLY), 1);
186
187 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000188 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000189 _exit (-1);
190 }
191
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000192 ui = _UPT_create (target_pid);
193
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000194 while (1)
195 {
196 pid = wait4 (-1, &status, 0, 0);
197 if (pid == -1)
198 {
199 if (errno == EINTR)
200 continue;
201
202 panic ("wait4() failed (errno=%d)\n", errno);
203 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000204 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000205 if (WIFSIGNALED (status) || WIFEXITED (status)
206 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
207 {
208 if (WIFEXITED (status))
209 {
210 if (WEXITSTATUS (status) != 0)
211 panic ("child's exit status %d\n", WEXITSTATUS (status));
212 break;
213 }
214 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000215 {
216 panic ("child terminated by signal %d\n", WTERMSIG (status));
217 break;
218 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000219 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000220 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000221 pending_sig = WSTOPSIG (status);
222 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000223 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000224 if (WSTOPSIG (status) == SIGUSR1)
225 state = 0;
226 else if (WSTOPSIG (status) == SIGUSR2)
227 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000228 }
229 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000230 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000231
232 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000233 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000234 case TRIGGER:
235 if (state)
236 ptrace (PTRACE_CONT, target_pid, 0, 0);
237 else
238 {
239 do_backtrace (target_pid);
240 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
241 }
242 break;
243
244 case SYSCALL:
245 if (!state)
246 do_backtrace (target_pid);
247 state ^= 1;
248 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
249 break;
250
251 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000252 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000253 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
254 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000255 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000256 }
257
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000258 _UPT_destroy (ui);
259
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000260 if (nerrors)
261 {
262 printf ("FAILURE: detected %d errors\n", nerrors);
263 exit (-1);
264 }
265 if (verbose)
266 printf ("SUCCESS\n");
267
268 return 0;
269}
mostang.com!davidmba424722004-05-04 22:19:18 +0000270
271#endif /* !HAVE_TTRACE */