blob: a34cf98a95b2f3b2577edfc04d650aac0acb4c99 [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
26#include <errno.h>
27#include <fcntl.h>
mostang.com!davidm40a15582004-01-21 01:05:07 +000028#include <libunwind-ptrace.h>
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000029#include <stdio.h>
30#include <stdlib.h>
hp.com!davidmb97fa142003-02-26 08:33:57 +000031#include <string.h>
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000032#include <unistd.h>
33
34#include <sys/ptrace.h>
35#include <sys/wait.h>
36
37int nerrors;
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000038int verbose;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000039int print_names = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000040
hp.com!davidmb97fa142003-02-26 08:33:57 +000041enum
42 {
43 INSTRUCTION,
44 SYSCALL,
45 TRIGGER
46 }
47trace_mode = SYSCALL;
48
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000049#define panic(args...) \
50 do { fprintf (stderr, args); ++nerrors; } while (0)
51
52static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000053static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000054
55void
56do_backtrace (pid_t target_pid)
57{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000058 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000059 unw_proc_info_t pi;
60 unw_word_t ip, sp;
61 unw_cursor_t c;
62 char buf[512];
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000063
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000064 ret = unw_init_remote (&c, as, ui);
65 if (ret < 0)
66 panic ("unw_init_remote() failed: ret=%d\n", ret);
67
68 do
69 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000070 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
71 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
72 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
73
mostang.com!davidma4bd80c2004-04-21 07:24:35 +000074 buf[0] = '\0';
75 if (print_names)
76 unw_get_proc_name (&c, buf, sizeof (buf), NULL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000078 if (verbose)
79 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000080
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000081 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
82 panic ("unw_get_proc_info() failed: ret=%d\n", ret);
83 else if (verbose)
84 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
85 (long) pi.start_ip, (long) pi.end_ip,
86 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000087
88#if UNW_TARGET_IA64
89 {
90 unw_word_t bsp;
91
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000092 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
93 panic ("unw_get_reg() failed: ret=%d\n", ret);
94 else if (verbose)
95 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000096 }
97#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000098 if (verbose)
99 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000100
101 ret = unw_step (&c);
102 if (ret < 0)
103 {
104 unw_get_reg (&c, UNW_REG_IP, &ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000105 panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
106 ret, (long) ip);
107 }
108
109 if (++n > 32)
110 {
111 /* guard against bad unwind info in old libraries... */
112 panic ("too deeply nested---assuming bogus unwind\n");
113 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000114 }
115 }
116 while (ret > 0);
117
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000118 if (ret < 0)
119 panic ("unwind failed with ret=%d\n", ret);
120
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000121 if (verbose)
122 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000123}
124
125int
126main (int argc, char **argv)
127{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000128 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000129 pid_t target_pid;
130
131 as = unw_create_addr_space (&_UPT_accessors, 0);
132 if (!as)
133 panic ("unw_create_addr_space() failed");
134
135 if (argc == 1)
136 {
137 char *args[] = { "self", "/bin/ls", "/usr", NULL };
138
139 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000140 argv = args;
141 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000142 else if (argc > 1)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000143 while (argv[optind][0] == '-')
144 {
145 if (strcmp (argv[optind], "-v") == 0)
146 ++optind, verbose = 1;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000147 else if (strcmp (argv[optind], "-i") == 0)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000148 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
149 else if (strcmp (argv[optind], "-s") == 0)
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000150 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000151 else if (strcmp (argv[optind], "-t") == 0)
152 /* Execute until syscall(-1), then backtrace at each insn. */
153 ++optind, trace_mode = TRIGGER;
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000154 else if (strcmp (argv[optind], "-c") == 0)
155 /* Enable caching of unwind-info. */
156 ++optind, unw_set_caching_policy (as, UNW_CACHE_GLOBAL);
157 else if (strcmp (argv[optind], "-n") == 0)
158 /* Don't look-up and print symbol names. */
159 ++optind, print_names = 0;
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000160 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000161
162 target_pid = fork ();
163 if (!target_pid)
164 {
165 /* child */
166
167 if (!verbose)
168 dup2 (open ("/dev/null", O_WRONLY), 1);
169
170 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000171 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000172 _exit (-1);
173 }
174
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000175 ui = _UPT_create (target_pid);
176
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000177 while (1)
178 {
179 pid = wait4 (-1, &status, 0, 0);
180 if (pid == -1)
181 {
182 if (errno == EINTR)
183 continue;
184
185 panic ("wait4() failed (errno=%d)\n", errno);
186 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000187 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000188 if (WIFSIGNALED (status) || WIFEXITED (status)
189 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
190 {
191 if (WIFEXITED (status))
192 {
193 if (WEXITSTATUS (status) != 0)
194 panic ("child's exit status %d\n", WEXITSTATUS (status));
195 break;
196 }
197 else if (WIFSIGNALED (status))
mostang.com!davidma4bd80c2004-04-21 07:24:35 +0000198 {
199 panic ("child terminated by signal %d\n", WTERMSIG (status));
200 break;
201 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000202 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000203 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000204 pending_sig = WSTOPSIG (status);
205 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000206 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000207 if (WSTOPSIG (status) == SIGUSR1)
208 state = 0;
209 else if (WSTOPSIG (status) == SIGUSR2)
210 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000211 }
212 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000213 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000214
215 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000216 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000217 case TRIGGER:
218 if (state)
219 ptrace (PTRACE_CONT, target_pid, 0, 0);
220 else
221 {
222 do_backtrace (target_pid);
223 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
224 }
225 break;
226
227 case SYSCALL:
228 if (!state)
229 do_backtrace (target_pid);
230 state ^= 1;
231 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
232 break;
233
234 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000235 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000236 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
237 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000238 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000239 }
240
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000241 _UPT_destroy (ui);
242
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000243 if (nerrors)
244 {
245 printf ("FAILURE: detected %d errors\n", nerrors);
246 exit (-1);
247 }
248 if (verbose)
249 printf ("SUCCESS\n");
250
251 return 0;
252}