blob: 4e733f68b4bdd988c9aa78e93c03cd023adfda24 [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>
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;
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)
hp.com!davidme6ddf4c2003-03-29 07:32:50 +0000140 while (argv[optind][0] == '-')
141 {
142 if (strcmp (argv[optind], "-v") == 0)
143 ++optind, verbose = 1;
144 if (strcmp (argv[optind], "-i") == 0)
145 ++optind, trace_mode = INSTRUCTION; /* backtrace at each insn */
146 else if (strcmp (argv[optind], "-s") == 0)
147 ++optind, trace_mode = SYSCALL; /* backtrace at each syscall */
148 else if (strcmp (argv[optind], "-t") == 0)
149 /* Execute until syscall(-1), then backtrace at each insn. */
150 ++optind, trace_mode = TRIGGER;
151 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000152
153 target_pid = fork ();
154 if (!target_pid)
155 {
156 /* child */
157
158 if (!verbose)
159 dup2 (open ("/dev/null", O_WRONLY), 1);
160
161 ptrace (PTRACE_TRACEME, 0, 0, 0);
hp.com!davidmb97fa142003-02-26 08:33:57 +0000162 execve (argv[optind], argv + optind, environ);
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000163 _exit (-1);
164 }
165
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000166 ui = _UPT_create (target_pid);
167
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000168 while (1)
169 {
170 pid = wait4 (-1, &status, 0, 0);
171 if (pid == -1)
172 {
173 if (errno == EINTR)
174 continue;
175
176 panic ("wait4() failed (errno=%d)\n", errno);
177 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000178 pending_sig = 0;
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000179 if (WIFSIGNALED (status) || WIFEXITED (status)
180 || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
181 {
182 if (WIFEXITED (status))
183 {
184 if (WEXITSTATUS (status) != 0)
185 panic ("child's exit status %d\n", WEXITSTATUS (status));
186 break;
187 }
188 else if (WIFSIGNALED (status))
189 panic ("child terminated by signal %d\n", WTERMSIG (status));
190 else
hp.com!davidmb97fa142003-02-26 08:33:57 +0000191 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000192 pending_sig = WSTOPSIG (status);
193 if (trace_mode == TRIGGER)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000194 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000195 if (WSTOPSIG (status) == SIGUSR1)
196 state = 0;
197 else if (WSTOPSIG (status) == SIGUSR2)
198 state = 1;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000199 }
200 }
hp.com!davidmb97fa142003-02-26 08:33:57 +0000201 }
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000202
203 switch (trace_mode)
hp.com!davidmb97fa142003-02-26 08:33:57 +0000204 {
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000205 case TRIGGER:
206 if (state)
207 ptrace (PTRACE_CONT, target_pid, 0, 0);
208 else
209 {
210 do_backtrace (target_pid);
211 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
212 }
213 break;
214
215 case SYSCALL:
216 if (!state)
217 do_backtrace (target_pid);
218 state ^= 1;
219 ptrace (PTRACE_SYSCALL, target_pid, 0, pending_sig);
220 break;
221
222 case INSTRUCTION:
hp.com!davidmb97fa142003-02-26 08:33:57 +0000223 do_backtrace (target_pid);
mostang.com!davidm64b4ac32003-02-27 09:58:57 +0000224 ptrace (PTRACE_SINGLESTEP, target_pid, 0, pending_sig);
225 break;
hp.com!davidmb97fa142003-02-26 08:33:57 +0000226 }
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000227 }
228
mostang.com!davidmde4410d2003-01-28 07:32:15 +0000229 _UPT_destroy (ui);
230
hp.com!davidme9e4e5f2003-01-28 03:40:06 +0000231 if (nerrors)
232 {
233 printf ("FAILURE: detected %d errors\n", nerrors);
234 exit (-1);
235 }
236 if (verbose)
237 printf ("SUCCESS\n");
238
239 return 0;
240}