15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* libunwind - a platform-independent unwind library
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   Copyright (C) 2002-2003 Hewlett-Packard Co
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)This file is part of libunwind.
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Permission is hereby granted, free of charge, to any person obtaining
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)a copy of this software and associated documentation files (the
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"Software"), to deal in the Software without restriction, including
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)without limitation the rights to use, copy, modify, merge, publish,
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)distribute, sublicense, and/or sell copies of the Software, and to
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)permit persons to whom the Software is furnished to do so, subject to
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)the following conditions:
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)The above copyright notice and this permission notice shall be
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)included in all copies or substantial portions of the Software.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* This file tests dynamic code-generation via function-cloning.  */
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "flush-cache.h"
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "compiler.h"
315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
325267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <libunwind.h>
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h>
345267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <stdlib.h>
355267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <string.h>
365267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <unistd.h>
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <signal.h>
383464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch#include <sys/mman.h>
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#if UNW_TARGET_ARM
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define MAX_FUNC_SIZE   96 	/* FIXME: arch/compiler dependent */
425267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#else
435267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#define MAX_FUNC_SIZE	2048	/* max. size of cloned function */
445267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#endif
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
465267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#define panic(args...)				\
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	{ fprintf (stderr, args); exit (-1); }
485267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
4906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)typedef void (*template_t) (int, void (*)(),
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			    int (*)(const char *, ...), const char *,
5106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)			    const char **);
5206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
5306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)int verbose;
5406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const char *strarr[] =
5606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)  {
573464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch    "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
585267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  };
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef __ia64__
615267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)struct fdesc
625267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  {
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    long code;
643464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch    long gp;
655267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)  };
665267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)# define get_fdesc(fdesc,func)	(fdesc = *(struct fdesc *) &(func))
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# define get_funcp(fdesc)	((template_t) &(fdesc))
6851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)# define get_gp(fdesc)		((fdesc).gp)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#elif __arm__
705267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)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
84struct 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
93void
94template (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
102static void
103sighandler (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
161int
162dev_null (const char *format UNUSED, ...)
163{
164  return 0;
165}
166
167int
168main (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 (&region->op[0], 0, -1, fdesc.code);
200  _U_dyn_op_stop (&region->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