blob: 04a124fea5b835ec172bc4d59d14869cf5cd0a76 [file] [log] [blame]
hp.com!davidme9e4e5f2003-01-28 03:40:06 +00001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2003 Hewlett-Packard Co
3 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>
28#include <libunwind.h>
29#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;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000039
hp.com!davidmb97fa142003-02-26 08:33:57 +000040enum
41 {
42 INSTRUCTION,
43 SYSCALL,
44 TRIGGER
45 }
46trace_mode = SYSCALL;
47
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000048#define panic(args...) \
49 do { fprintf (stderr, args); ++nerrors; } while (0)
50
51static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000052static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000053
54void
55do_backtrace (pid_t target_pid)
56{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000057 int n = 0, ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000058 unw_proc_info_t pi;
59 unw_word_t ip, sp;
60 unw_cursor_t c;
61 char buf[512];
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000062
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000063 ret = unw_init_remote (&c, as, ui);
64 if (ret < 0)
65 panic ("unw_init_remote() failed: ret=%d\n", ret);
66
67 do
68 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000069 if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
70 || (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
71 panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
72
mostang.com!davidmd20530f2003-02-08 10:10:59 +000073 unw_get_proc_name (&c, buf, sizeof (buf), NULL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000074
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000075 if (verbose)
76 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000077
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000078 if ((ret = unw_get_proc_info (&c, &pi)) < 0)
79 panic ("unw_get_proc_info() failed: ret=%d\n", ret);
80 else if (verbose)
81 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
82 (long) pi.start_ip, (long) pi.end_ip,
83 (long) pi.handler, (long) pi.lsda);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000084
85#if UNW_TARGET_IA64
86 {
87 unw_word_t bsp;
88
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000089 if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
90 panic ("unw_get_reg() failed: ret=%d\n", ret);
91 else if (verbose)
92 printf (" bsp=%lx", bsp);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000093 }
94#endif
mostang.com!davidm64b4ac32003-02-27 09:58:57 +000095 if (verbose)
96 printf ("\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000097
98 ret = unw_step (&c);
99 if (ret < 0)
100 {
101 unw_get_reg (&c, UNW_REG_IP, &ip);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000102 panic ("FAILURE: unw_step() returned %d for ip=%lx\n",
103 ret, (long) ip);
104 }
105
106 if (++n > 32)
107 {
108 /* guard against bad unwind info in old libraries... */
109 panic ("too deeply nested---assuming bogus unwind\n");
110 break;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000111 }
112 }
113 while (ret > 0);
114
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000115 if (ret < 0)
116 panic ("unwind failed with ret=%d\n", ret);
117
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000118 if (verbose)
119 printf ("================\n\n");
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000120}
121
122int
123main (int argc, char **argv)
124{
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000125 int status, pid, pending_sig, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000126 pid_t target_pid;
127
128 as = unw_create_addr_space (&_UPT_accessors, 0);
129 if (!as)
130 panic ("unw_create_addr_space() failed");
131
132 if (argc == 1)
133 {
134 char *args[] = { "self", "/bin/ls", "/usr", NULL };
135
136 /* automated test case */
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000137 argv = args;
138 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000139 else if (argc > 1)
140 {
141 if (strcmp (argv[optind], "-v") == 0)
142 ++optind, verbose = 1;
143 if (strcmp (argv[optind], "-i") == 0)
144 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
145 else if (strcmp (argv[optind], "-s") == 0)
146 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
147 else if (strcmp (argv[optind], "-t") == 0)
148 /* Execute until syscall(-1), then backtrace at each insn. */
149 ++optind, trace_mode = TRIGGER;
150 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000151
152 target_pid = fork ();
153 if (!target_pid)
154 {
155 /* child */
156
157 if (!verbose)
158 dup2 (open ("/dev/null", O_WRONLY), 1);
159
160 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000161 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000162 _exit (-1);
163 }
164
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000165 ui = _UPT_create (target_pid);
166
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000167 while (1)
168 {
169 pid = wait4 (-1, &status, 0, 0);
170 if (pid == -1)
171 {
172 if (errno == EINTR)
173 continue;
174
175 panic ("wait4() failed (errno=%d)\n", errno);
176 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000177 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000178 if (WIFSIGNALED (status) || WIFEXITED (status)
179 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
180 {
181 if (WIFEXITED (status))
182 {
183 if (WEXITSTATUS (status) != 0)
184 panic ("child's exit status %d\n", WEXITSTATUS (status));
185 break;
186 }
187 else if (WIFSIGNALED (status))
188 panic ("child terminated by signal %d\n", WTERMSIG (status));
189 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000190 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000191 pending_sig = WSTOPSIG (status);
192 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000193 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000194 if (WSTOPSIG (status) == SIGUSR1)
195 state = 0;
196 else if (WSTOPSIG (status) == SIGUSR2)
197 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000198 }
199 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000200 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000201
202 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000203 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000204 case TRIGGER:
205 if (state)
206 ptrace (PTRACE_CONT, target_pid, 0, 0);
207 else
208 {
209 do_backtrace (target_pid);
210 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
211 }
212 break;
213
214 case SYSCALL:
215 if (!state)
216 do_backtrace (target_pid);
217 state ^= 1;
218 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
219 break;
220
221 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000222 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000223 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
224 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000225 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000226 }
227
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000228 _UPT_destroy (ui);
229
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000230 if (nerrors)
231 {
232 printf ("FAILURE: detected %d errors\n", nerrors);
233 exit (-1);
234 }
235 if (verbose)
236 printf ("SUCCESS\n");
237
238 return 0;
239}