blob: 2e03b866ac076714a0df6bf86044eb36dff7a1bb [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
hp.com!davidmb97fa142003-02-26 08:33:57 +000037#ifdef __ia64__
38# include <asm/ptrace_offsets.h>
39#endif
40
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000041int nerrors;
42int verbose = 1;
43
hp.com!davidmb97fa142003-02-26 08:33:57 +000044enum
45 {
46 INSTRUCTION,
47 SYSCALL,
48 TRIGGER
49 }
50trace_mode = SYSCALL;
51
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000052#define panic(args...) \
53 do { fprintf (stderr, args); ++nerrors; } while (0)
54
55static unw_addr_space_t as;
mostang.com!davidmde4410d2003-01-28 07:32:15 +000056static struct UPT_info *ui;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000057
58void
59do_backtrace (pid_t target_pid)
60{
hp.com!davidmb97fa142003-02-26 08:33:57 +000061 int ret;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000062 unw_proc_info_t pi;
63 unw_word_t ip, sp;
64 unw_cursor_t c;
65 char buf[512];
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000066
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000067 ret = unw_init_remote (&c, as, ui);
68 if (ret < 0)
69 panic ("unw_init_remote() failed: ret=%d\n", ret);
70
71 do
72 {
73 unw_get_reg (&c, UNW_REG_IP, &ip);
74 unw_get_reg (&c, UNW_REG_SP, &sp);
mostang.com!davidmd20530f2003-02-08 10:10:59 +000075 unw_get_proc_name (&c, buf, sizeof (buf), NULL);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +000076
77 printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
78
79 unw_get_proc_info (&c, &pi);
80 printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx",
81 (long) pi.start_ip, (long) pi.end_ip,
82 (long) pi.handler, (long) pi.lsda);
83
84#if UNW_TARGET_IA64
85 {
86 unw_word_t bsp;
87
88 unw_get_reg (&c, UNW_IA64_BSP, &bsp);
89 printf (" bsp=%lx", bsp);
90 }
91#endif
92 printf ("\n");
93
94 ret = unw_step (&c);
95 if (ret < 0)
96 {
97 unw_get_reg (&c, UNW_REG_IP, &ip);
98 printf ("FAILURE: unw_step() returned %d for ip=%lx\n",
99 ret, (long) ip);
100 }
101 }
102 while (ret > 0);
103
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000104 if (ret < 0)
105 panic ("unwind failed with ret=%d\n", ret);
106
107 printf ("================\n\n");
108}
109
110int
111main (int argc, char **argv)
112{
hp.com!davidmb97fa142003-02-26 08:33:57 +0000113 int syscall_number, status, pid, optind = 1, state = 1;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000114 pid_t target_pid;
115
116 as = unw_create_addr_space (&_UPT_accessors, 0);
117 if (!as)
118 panic ("unw_create_addr_space() failed");
119
120 if (argc == 1)
121 {
122 char *args[] = { "self", "/bin/ls", "/usr", NULL };
123
124 /* automated test case */
125 verbose = 0;
126 argv = args;
127 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000128 else if (argc > 1)
129 {
130 if (strcmp (argv[optind], "-v") == 0)
131 ++optind, verbose = 1;
132 if (strcmp (argv[optind], "-i") == 0)
133 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
134 else if (strcmp (argv[optind], "-s") == 0)
135 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
136 else if (strcmp (argv[optind], "-t") == 0)
137 /* Execute until syscall(-1), then backtrace at each insn. */
138 ++optind, trace_mode = TRIGGER;
139 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000140
141 target_pid = fork ();
142 if (!target_pid)
143 {
144 /* child */
145
146 if (!verbose)
147 dup2 (open ("/dev/null", O_WRONLY), 1);
148
149 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000150 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000151 _exit (-1);
152 }
153
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000154 ui = _UPT_create (target_pid);
155
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000156 while (1)
157 {
158 pid = wait4 (-1, &status, 0, 0);
159 if (pid == -1)
160 {
161 if (errno == EINTR)
162 continue;
163
164 panic ("wait4() failed (errno=%d)\n", errno);
165 }
166 if (WIFSIGNALED (status) || WIFEXITED (status)
167 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
168 {
169 if (WIFEXITED (status))
170 {
171 if (WEXITSTATUS (status) != 0)
172 panic ("child's exit status %d\n", WEXITSTATUS (status));
173 break;
174 }
175 else if (WIFSIGNALED (status))
176 panic ("child terminated by signal %d\n", WTERMSIG (status));
177 else
178 panic ("child got signal %d\n", WSTOPSIG (status));
179 }
180
hp.com!davidmb97fa142003-02-26 08:33:57 +0000181 if (trace_mode == SYSCALL || trace_mode == TRIGGER)
182 {
183 if (!state)
184 {
185 if (trace_mode == SYSCALL)
186 do_backtrace (target_pid);
187 }
188 else
189 {
190 errno = 0;
191 syscall_number = ptrace (PTRACE_PEEKUSER, target_pid, PT_R15, 0);
192 if (errno != 0)
193 syscall_number = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000194
hp.com!davidmb97fa142003-02-26 08:33:57 +0000195 printf ("syscall = %d\n", syscall_number);
196
197 if (trace_mode == TRIGGER && syscall_number == -1)
198 {
199 trace_mode = INSTRUCTION;
200 goto do_insn;
201 }
202 }
203
204 state ^= 1;
205 ptrace (PTRACE_SYSCALL, target_pid, 0, 0); /* continue */
206 }
207 else
208 {
209 do_backtrace (target_pid);
210 do_insn:
211 ptrace (PTRACE_SINGLESTEP, target_pid, 0, 0); /* continue */
212 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000213 }
214
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000215 _UPT_destroy (ui);
216
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000217 if (nerrors)
218 {
219 printf ("FAILURE: detected %d errors\n", nerrors);
220 exit (-1);
221 }
222 if (verbose)
223 printf ("SUCCESS\n");
224
225 return 0;
226}