blob: 5e3f1a3f963e9b8a084d9324f2b21a0f04afe1c3 [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
hp.com!davidmc9a01bf2004-04-21 23:46:17 +000037#define MAX_FUNC_SIZE 2048 /* max. size of cloned function */
38
hp.com!davidma1aed8c2003-02-22 03:08:22 +000039#define panic(args...) \
40 { fprintf (stderr, args); exit (-1); }
41
42typedef void (*template_t) (int, void (*)(),
43 int (*)(const char *, ...), const char *,
44 const char **);
45
46int verbose;
47
48static const char *strarr[] =
49 {
50 "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
51 };
52
53#ifdef __ia64__
54struct fdesc
55 {
56 long code;
57 long gp;
58 };
59# define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func))
60# define get_funcp(fdesc) ((template_t) &(fdesc))
61# define get_gp(fdesc) ((fdesc).gp)
62#else
63struct fdesc
64 {
65 long code;
66 };
67# define get_fdesc(fdesc,func) (fdesc.code = (long) &(func))
68# define get_funcp(fdesc) ((template_t) (fdesc).code)
69# define get_gp(fdesc) (0)
70#endif
71
mostang.com!davidm0e2f4862003-03-27 04:29:07 +000072extern void flush_cache (void *addr, size_t len);
hp.com!davidma1aed8c2003-02-22 03:08:22 +000073
74void
75template (int i, template_t self,
76 int (*printer)(const char *, ...), const char *fmt, const char **arr)
77{
78 (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
79 if (i > 0)
80 (*self) (i - 1, self, printer, fmt, arr);
81}
82
83static void
84sighandler (int signal)
85{
86 unw_cursor_t cursor;
87 char name[128], off[32];
88 unw_word_t ip, offset;
89 unw_context_t uc;
90 int count = 0;
91
92 if (verbose)
93 printf ("caught signal %d\n", signal);
94
95 unw_getcontext (&uc);
96 unw_init_local (&cursor, &uc);
97
98 while (!unw_is_signal_frame (&cursor))
99 if (unw_step (&cursor) < 0)
100 panic ("failed to find signal frame!\n");
101 unw_step (&cursor);
102
103 do
104 {
105 unw_get_reg (&cursor, UNW_REG_IP, &ip);
106 name[0] = '\0';
107 off[0] = '\0';
108 if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
109 && off > 0)
110 snprintf (off, sizeof (off), "+0x%lx", (long) offset);
111 if (verbose)
112 printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
113 ++count;
114 }
115 while (unw_step (&cursor) > 0);
116
117 if (count != 13)
118 panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
119
120 if (verbose)
121 printf ("SUCCESS\n");
122 exit (0);
123}
124
125int
126dev_null (const char *format, ...)
127{
128 return 0;
129}
130
131int
132main (int argc, char *argv[])
133{
134 unw_dyn_region_info_t *region;
135 unw_dyn_info_t di;
136 struct fdesc fdesc;
137 template_t funcp;
138 void *mem;
139
140 if (argc > 1)
141 ++verbose;
142
143 mem = malloc (getpagesize ());
144
145 get_fdesc (fdesc, template);
146
147 if (verbose)
148 printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
149
hp.com!davidmc9a01bf2004-04-21 23:46:17 +0000150 memcpy (mem, (void *) fdesc.code, MAX_FUNC_SIZE);
hp.com!davidma1aed8c2003-02-22 03:08:22 +0000151 mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
152 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
hp.com!davidmc9a01bf2004-04-21 23:46:17 +0000153 flush_cache (mem, MAX_FUNC_SIZE);
hp.com!davidma1aed8c2003-02-22 03:08:22 +0000154
155 signal (SIGSEGV, sighandler);
156
157 /* register the new function: */
158 region = alloca (_U_dyn_region_info_size (2));
159 region->next = NULL;
hp.com!davidmc9a01bf2004-04-21 23:46:17 +0000160 region->insn_count = 3 * (MAX_FUNC_SIZE / 16);
hp.com!davidma1aed8c2003-02-22 03:08:22 +0000161 region->op_count = 2;
162 _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
163 _U_dyn_op_stop (&region->op[1]);
164
165 memset (&di, 0, sizeof (di));
166 di.start_ip = (long) mem;
mostang.com!davidm6bf5cdd2003-03-28 07:43:22 +0000167 di.end_ip = (long) mem + 16*region->insn_count/3;
hp.com!davidma1aed8c2003-02-22 03:08:22 +0000168 di.gp = get_gp (fdesc);
169 di.format = UNW_INFO_FORMAT_DYNAMIC;
170 di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
171 di.u.pi.regions = region;
172
173 _U_dyn_register (&di);
174
175 /* call new function: */
176 fdesc.code = (long) mem;
177 funcp = get_funcp (fdesc);
178
179 if (verbose)
180 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
181 else
182 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr);
183
184 _U_dyn_cancel (&di);
185 return -1;
186}