1 /* 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
5 This file is part of libunwind.
6
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH 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 "flush-cache.h"
29
30 #include "compiler.h"
31
32 #include <libunwind.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <sys/mman.h>
39
40 #if UNW_TARGET_ARM
41 #define MAX_FUNC_SIZE 96 /* FIXME: arch/compiler dependent */
42 #else
43 #define MAX_FUNC_SIZE 2048 /* max. size of cloned function */
44 #endif
45
46 #define panic(args...) \
47 { fprintf (stderr, args); exit (-1); }
48
49 typedef void (*template_t) (int, void (*)(),
50 int (*)(const char *, ...), const char *,
51 const char **);
52
53 int verbose;
54
55 static const char *strarr[] =
56 {
57 "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
58 };
59
60 #ifdef __ia64__
61 struct fdesc
62 {
63 long code;
64 long gp;
65 };
66 # define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func))
67 # define get_funcp(fdesc) ((template_t) &(fdesc))
68 # define get_gp(fdesc) ((fdesc).gp)
69 #elif __arm__
70 struct fdesc
71 {
72 long code;
73 long is_thumb;
74 };
75 /* Workaround GCC bug: https://bugs.launchpad.net/gcc-linaro/+bug/721531 */
76 # define get_fdesc(fdesc,func) ({long tmp = (long) &(func); \
77 (fdesc).code = (long) &(func) & ~0x1; \
78 (fdesc).is_thumb = tmp & 0x1;})
79 /*# define get_fdesc(fdesc,func) ({(fdesc).code = (long) &(func) & ~0x1; \
80 (fdesc).is_thumb = (long) &(func) & 0x1;})*/
81 # define get_funcp(fdesc) ((template_t) ((fdesc).code | (fdesc).is_thumb))
82 # define get_gp(fdesc) (0)
83 #else
84 struct fdesc
85 {
86 long code;
87 };
88 # define get_fdesc(fdesc,func) (fdesc.code = (long) &(func))
89 # define get_funcp(fdesc) ((template_t) (fdesc).code)
90 # define get_gp(fdesc) (0)
91 #endif
92
93 void
template(int i,template_t self,int (* printer)(const char *,...),const char * fmt,const char ** arr)94 template (int i, template_t self,
95 int (*printer)(const char *, ...), const char *fmt, const char **arr)
96 {
97 (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
98 if (i > 0)
99 (*self) (i - 1, self, printer, fmt, arr);
100 }
101
102 static void
sighandler(int signal)103 sighandler (int signal)
104 {
105 unw_cursor_t cursor;
106 char name[128], off[32];
107 unw_word_t ip, offset;
108 unw_context_t uc;
109 int count;
110
111 if (verbose)
112 printf ("caught signal %d\n", signal);
113
114 unw_getcontext (&uc);
115 unw_init_local (&cursor, &uc);
116
117 count = 0;
118 while (!unw_is_signal_frame (&cursor))
119 {
120 if (unw_step (&cursor) < 0)
121 panic ("failed to find signal frame!\n");
122
123 if (count++ > 20)
124 {
125 panic ("Too many steps to the signal frame (%d)\n", count);
126 break;
127 }
128 }
129 unw_step (&cursor);
130
131 count = 0;
132 do
133 {
134 unw_get_reg (&cursor, UNW_REG_IP, &ip);
135 name[0] = '\0';
136 off[0] = '\0';
137 if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
138 && offset > 0)
139 snprintf (off, sizeof (off), "+0x%lx", (long) offset);
140 if (verbose)
141 printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
142 ++count;
143
144 if (count > 20)
145 {
146 panic ("Too many steps (%d)\n", count);
147 break;
148 }
149
150 }
151 while (unw_step (&cursor) > 0);
152
153 if (count != 13)
154 panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
155
156 if (verbose)
157 printf ("SUCCESS\n");
158 exit (0);
159 }
160
161 int
dev_null(const char * format UNUSED,...)162 dev_null (const char *format UNUSED, ...)
163 {
164 return 0;
165 }
166
167 int
main(int argc,char * argv[]UNUSED)168 main (int argc, char *argv[] UNUSED)
169 {
170 unw_dyn_region_info_t *region;
171 unw_dyn_info_t di;
172 struct fdesc fdesc;
173 template_t funcp;
174 void *mem;
175
176 if (argc > 1)
177 ++verbose;
178
179 mem = malloc (getpagesize ());
180
181 get_fdesc (fdesc, template);
182
183 if (verbose)
184 printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
185
186 memcpy (mem, (void *) fdesc.code, MAX_FUNC_SIZE);
187 mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
188 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
189
190 flush_cache (mem, MAX_FUNC_SIZE);
191
192 signal (SIGSEGV, sighandler);
193
194 /* register the new function: */
195 region = alloca (_U_dyn_region_info_size (2));
196 region->next = NULL;
197 region->insn_count = 3 * (MAX_FUNC_SIZE / 16);
198 region->op_count = 2;
199 _U_dyn_op_alias (®ion->op[0], 0, -1, fdesc.code);
200 _U_dyn_op_stop (®ion->op[1]);
201
202 memset (&di, 0, sizeof (di));
203 di.start_ip = (long) mem;
204 di.end_ip = (long) mem + 16*region->insn_count/3;
205 di.gp = get_gp (fdesc);
206 di.format = UNW_INFO_FORMAT_DYNAMIC;
207 di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
208 di.u.pi.regions = region;
209
210 _U_dyn_register (&di);
211
212 /* call new function: */
213 fdesc.code = (long) mem;
214 funcp = get_funcp (fdesc);
215
216 if (verbose)
217 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
218 else
219 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr);
220
221 _U_dyn_cancel (&di);
222 return -1;
223 }
224