blob: fa63a3c56ccddf444446ae235aad7e13cc213173 [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
mostang.com!davidm0e2f4862003-03-27 04:29:07 +000070extern void flush_cache (void *addr, size_t len);
hp.com!davidma1aed8c2003-02-22 03:08:22 +000071
72void
73template (int i, template_t self,
74 int (*printer)(const char *, ...), const char *fmt, const char **arr)
75{
76 (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
77 if (i > 0)
78 (*self) (i - 1, self, printer, fmt, arr);
79}
80
81static void
82sighandler (int signal)
83{
84 unw_cursor_t cursor;
85 char name[128], off[32];
86 unw_word_t ip, offset;
87 unw_context_t uc;
88 int count = 0;
89
90 if (verbose)
91 printf ("caught signal %d\n", signal);
92
93 unw_getcontext (&uc);
94 unw_init_local (&cursor, &uc);
95
96 while (!unw_is_signal_frame (&cursor))
97 if (unw_step (&cursor) < 0)
98 panic ("failed to find signal frame!\n");
99 unw_step (&cursor);
100
101 do
102 {
103 unw_get_reg (&cursor, UNW_REG_IP, &ip);
104 name[0] = '\0';
105 off[0] = '\0';
106 if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
107 && off > 0)
108 snprintf (off, sizeof (off), "+0x%lx", (long) offset);
109 if (verbose)
110 printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
111 ++count;
112 }
113 while (unw_step (&cursor) > 0);
114
115 if (count != 13)
116 panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
117
118 if (verbose)
119 printf ("SUCCESS\n");
120 exit (0);
121}
122
123int
124dev_null (const char *format, ...)
125{
126 return 0;
127}
128
129int
130main (int argc, char *argv[])
131{
132 unw_dyn_region_info_t *region;
133 unw_dyn_info_t di;
134 struct fdesc fdesc;
135 template_t funcp;
136 void *mem;
137
138 if (argc > 1)
139 ++verbose;
140
141 mem = malloc (getpagesize ());
142
143 get_fdesc (fdesc, template);
144
145 if (verbose)
146 printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
147
148 memcpy (mem, (void *) fdesc.code, 256);
149 mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
150 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
151 flush_cache (mem, 256);
152
153 signal (SIGSEGV, sighandler);
154
155 /* register the new function: */
156 region = alloca (_U_dyn_region_info_size (2));
157 region->next = NULL;
158 region->insn_count = 256;
159 region->op_count = 2;
160 _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
161 _U_dyn_op_stop (&region->op[1]);
162
163 memset (&di, 0, sizeof (di));
164 di.start_ip = (long) mem;
mostang.com!davidm6bf5cdd2003-03-28 07:43:22 +0000165 di.end_ip = (long) mem + 16*region->insn_count/3;
hp.com!davidma1aed8c2003-02-22 03:08:22 +0000166 di.gp = get_gp (fdesc);
167 di.format = UNW_INFO_FORMAT_DYNAMIC;
168 di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
169 di.u.pi.regions = region;
170
171 _U_dyn_register (&di);
172
173 /* call new function: */
174 fdesc.code = (long) mem;
175 funcp = get_funcp (fdesc);
176
177 if (verbose)
178 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
179 else
180 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr);
181
182 _U_dyn_cancel (&di);
183 return -1;
184}