blob: 0d920cf24ff597c6c2b488d9c3c016e6eb47c9d0 [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!davidme9e4e5f2003-01-28 03:40:06 +000062#define panic(args...) \
63 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;
73 unw_word_t ip, sp;
74 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
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000087 buf[0] = '\0';
88 if (print_names)
89 unw_get_proc_name (&c, buf, sizeof (buf), NULL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000090
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000091 if (verbose)
92 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000093
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000094 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
95 panic ("unw_get_proc_info() failed: ret=%d\n", ret);
96 else if (verbose)
97 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
98 (long) pi.start_ip, (long) pi.end_ip,
99 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000100
101#if UNW_TARGET_IA64
102 {
103 unw_word_t bsp;
104
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000105 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
106 panic ("unw_get_reg() failed: ret=%d\n", ret);
107 else if (verbose)
108 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000109 }
110#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000111 if (verbose)
112 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000113
114 ret = unw_step (&c);
115 if (ret < 0)
116 {
117 unw_get_reg (&c, UNW_REG_IP, &ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000118 panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
119 ret, (long) ip);
120 }
121
122 if (++n > 32)
123 {
124 /* guard against bad unwind info in old libraries... */
125 panic ("too deeply nested---assuming bogus unwind\n");
126 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000127 }
128 }
129 while (ret > 0);
130
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000131 if (ret < 0)
132 panic ("unwind failed with ret=%d\n", ret);
133
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000134 if (verbose)
135 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000136}
137
138int
139main (int argc, char **argv)
140{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000141 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000142 pid_t target_pid;
143
144 as = unw_create_addr_space (&_UPT_accessors, 0);
145 if (!as)
146 panic ("unw_create_addr_space() failed");
147
148 if (argc == 1)
149 {
150 char *args[] = { "self", "/bin/ls", "/usr", NULL };
151
152 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000153 argv = args;
154 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000155 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000156 while (argv[optind][0] == '-')
157 {
158 if (strcmp (argv[optind], "-v") == 0)
159 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000160 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000161 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
162 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000163 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000164 else if (strcmp (argv[optind], "-t") == 0)
165 /* Execute until syscall(-1), then backtrace at each insn. */
166 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000167 else if (strcmp (argv[optind], "-c") == 0)
168 /* Enable caching of unwind-info. */
169 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
170 else if (strcmp (argv[optind], "-n") == 0)
171 /* Don't look-up and print symbol names. */
172 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000173 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000174
175 target_pid = fork ();
176 if (!target_pid)
177 {
178 /* child */
179
180 if (!verbose)
181 dup2 (open ("/dev/null", O_WRONLY), 1);
182
183 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000184 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000185 _exit (-1);
186 }
187
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000188 ui = _UPT_create (target_pid);
189
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000190 while (1)
191 {
192 pid = wait4 (-1, &status, 0, 0);
193 if (pid == -1)
194 {
195 if (errno == EINTR)
196 continue;
197
198 panic ("wait4() failed (errno=%d)\n", errno);
199 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000200 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000201 if (WIFSIGNALED (status) || WIFEXITED (status)
202 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
203 {
204 if (WIFEXITED (status))
205 {
206 if (WEXITSTATUS (status) != 0)
207 panic ("child's exit status %d\n", WEXITSTATUS (status));
208 break;
209 }
210 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000211 {
212 panic ("child terminated by signal %d\n", WTERMSIG (status));
213 break;
214 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000215 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000216 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000217 pending_sig = WSTOPSIG (status);
218 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000219 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000220 if (WSTOPSIG (status) == SIGUSR1)
221 state = 0;
222 else if (WSTOPSIG (status) == SIGUSR2)
223 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000224 }
225 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000226 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000227
228 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000229 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000230 case TRIGGER:
231 if (state)
232 ptrace (PTRACE_CONT, target_pid, 0, 0);
233 else
234 {
235 do_backtrace (target_pid);
236 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
237 }
238 break;
239
240 case SYSCALL:
241 if (!state)
242 do_backtrace (target_pid);
243 state ^= 1;
244 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
245 break;
246
247 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000248 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000249 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
250 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000251 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000252 }
253
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000254 _UPT_destroy (ui);
255
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000256 if (nerrors)
257 {
258 printf ("FAILURE: detected %d errors\n", nerrors);
259 exit (-1);
260 }
261 if (verbose)
262 printf ("SUCCESS\n");
263
264 return 0;
265}
mostang.com!davidmba424722004-05-04 22:19:18 +0000266
267#endif /* !HAVE_TTRACE */