blob: dbfe1dd0db2cf18c0b4a84719d1e55599442e351 [file] [log] [blame]
hp.com!davidma1aed8c2003-02-22 03:08:22 +00001/* libunwind - a platform-independent unwind library
2 Copyright (C) 2002-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/* This file tests dynamic code-generation via function-cloning. */
27
28#include <libunwind.h>
29#include <malloc.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <sys/mman.h>
36
37#define panic(args...) \
38 { fprintf (stderr, args); exit (-1); }
39
40typedef void (*template_t) (int, void (*)(),
41 int (*)(const char *, ...), const char *,
42 const char **);
43
44int verbose;
45
46static const char *strarr[] =
47 {
48 "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
49 };
50
51#ifdef __ia64__
52struct fdesc
53 {
54 long code;
55 long gp;
56 };
57# define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func))
58# define get_funcp(fdesc) ((template_t) &(fdesc))
59# define get_gp(fdesc) ((fdesc).gp)
60#else
61struct fdesc
62 {
63 long code;
64 };
65# define get_fdesc(fdesc,func) (fdesc.code = (long) &(func))
66# define get_funcp(fdesc) ((template_t) (fdesc).code)
67# define get_gp(fdesc) (0)
68#endif
69
70static void
71flush_cache (void *addr, unsigned long len)
72{
73#ifdef __ia64__
74 void *end = (char *) addr + len;
75
76 while (addr < end)
77 {
78 asm volatile ("fc %0" :: "r"(addr));
79 addr = (char *) addr + 32;
80 }
81 asm volatile (";;sync.i;;srlz.i;;");
82#endif
83}
84
85void
86template (int i, template_t self,
87 int (*printer)(const char *, ...), const char *fmt, const char **arr)
88{
89 (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
90 if (i > 0)
91 (*self) (i - 1, self, printer, fmt, arr);
92}
93
94static void
95sighandler (int signal)
96{
97 unw_cursor_t cursor;
98 char name[128], off[32];
99 unw_word_t ip, offset;
100 unw_context_t uc;
101 int count = 0;
102
103 if (verbose)
104 printf ("caught signal %d\n", signal);
105
106 unw_getcontext (&uc);
107 unw_init_local (&cursor, &uc);
108
109 while (!unw_is_signal_frame (&cursor))
110 if (unw_step (&cursor) < 0)
111 panic ("failed to find signal frame!\n");
112 unw_step (&cursor);
113
114 do
115 {
116 unw_get_reg (&cursor, UNW_REG_IP, &ip);
117 name[0] = '\0';
118 off[0] = '\0';
119 if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
120 && off > 0)
121 snprintf (off, sizeof (off), "+0x%lx", (long) offset);
122 if (verbose)
123 printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
124 ++count;
125 }
126 while (unw_step (&cursor) > 0);
127
128 if (count != 13)
129 panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
130
131 if (verbose)
132 printf ("SUCCESS\n");
133 exit (0);
134}
135
136int
137dev_null (const char *format, ...)
138{
139 return 0;
140}
141
142int
143main (int argc, char *argv[])
144{
145 unw_dyn_region_info_t *region;
146 unw_dyn_info_t di;
147 struct fdesc fdesc;
148 template_t funcp;
149 void *mem;
150
151 if (argc > 1)
152 ++verbose;
153
154 mem = malloc (getpagesize ());
155
156 get_fdesc (fdesc, template);
157
158 if (verbose)
159 printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
160
161 memcpy (mem, (void *) fdesc.code, 256);
162 mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
163 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
164 flush_cache (mem, 256);
165
166 signal (SIGSEGV, sighandler);
167
168 /* register the new function: */
169 region = alloca (_U_dyn_region_info_size (2));
170 region->next = NULL;
171 region->insn_count = 256;
172 region->op_count = 2;
173 _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
174 _U_dyn_op_stop (&region->op[1]);
175
176 memset (&di, 0, sizeof (di));
177 di.start_ip = (long) mem;
178 di.end_ip = (long) mem + 256;
179 di.gp = get_gp (fdesc);
180 di.format = UNW_INFO_FORMAT_DYNAMIC;
181 di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
182 di.u.pi.regions = region;
183
184 _U_dyn_register (&di);
185
186 /* call new function: */
187 fdesc.code = (long) mem;
188 funcp = get_funcp (fdesc);
189
190 if (verbose)
191 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
192 else
193 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr);
194
195 _U_dyn_cancel (&di);
196 return -1;
197}