Gtest-dyn1.c revision 570c09a2afe255ce30b64e3298218ffbcff73e80
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
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#if UNW_TARGET_ARM
38#define MAX_FUNC_SIZE   96 	/* FIXME: arch/compiler dependent */
39#else
40#define MAX_FUNC_SIZE	2048	/* max. size of cloned function */
41#endif
42
43#define panic(args...)				\
44	{ fprintf (stderr, args); exit (-1); }
45
46typedef void (*template_t) (int, void (*)(),
47			    int (*)(const char *, ...), const char *,
48			    const char **);
49
50int verbose;
51
52static const char *strarr[] =
53  {
54    "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
55  };
56
57#ifdef __ia64__
58struct fdesc
59  {
60    long code;
61    long gp;
62  };
63# define get_fdesc(fdesc,func)	(fdesc = *(struct fdesc *) &(func))
64# define get_funcp(fdesc)	((template_t) &(fdesc))
65# define get_gp(fdesc)		((fdesc).gp)
66#else
67struct fdesc
68  {
69    long code;
70  };
71# define get_fdesc(fdesc,func)	(fdesc.code = (long) &(func))
72# define get_funcp(fdesc)	((template_t) (fdesc).code)
73# define get_gp(fdesc)		(0)
74#endif
75
76extern void flush_cache (void *addr, size_t len);
77
78void
79template (int i, template_t self,
80	  int (*printer)(const char *, ...), const char *fmt, const char **arr)
81{
82  (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
83  if (i > 0)
84    (*self) (i - 1, self, printer, fmt, arr);
85}
86
87static void
88sighandler (int signal)
89{
90  unw_cursor_t cursor;
91  char name[128], off[32];
92  unw_word_t ip, offset;
93  unw_context_t uc;
94  int count;
95
96  if (verbose)
97    printf ("caught signal %d\n", signal);
98
99  unw_getcontext (&uc);
100  unw_init_local (&cursor, &uc);
101
102  count = 0;
103  while (!unw_is_signal_frame (&cursor))
104    {
105      if (unw_step (&cursor) < 0)
106	panic ("failed to find signal frame!\n");
107
108      if (count++ > 20)
109	{
110	  panic ("Too many steps to the signal frame (%d)\n", count);
111	  break;
112	}
113    }
114  unw_step (&cursor);
115
116  count = 0;
117  do
118    {
119      unw_get_reg (&cursor, UNW_REG_IP, &ip);
120      name[0] = '\0';
121      off[0] = '\0';
122      if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0
123	  && offset > 0)
124	snprintf (off, sizeof (off), "+0x%lx", (long) offset);
125      if (verbose)
126	printf ("ip = %lx <%s%s>\n", (long) ip, name, off);
127      ++count;
128
129      if (count > 20)
130	{
131	  panic ("Too many steps (%d)\n", count);
132	  break;
133	}
134
135    }
136  while (unw_step (&cursor) > 0);
137
138  if (count != 13)
139    panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
140
141  if (verbose)
142    printf ("SUCCESS\n");
143  exit (0);
144}
145
146int
147dev_null (const char *format, ...)
148{
149  return 0;
150}
151
152int
153main (int argc, char *argv[])
154{
155  unw_dyn_region_info_t *region;
156  unw_dyn_info_t di;
157  struct fdesc fdesc;
158  template_t funcp;
159  void *mem;
160
161  if (argc > 1)
162    ++verbose;
163
164  mem = malloc (getpagesize ());
165
166  get_fdesc (fdesc, template);
167
168  if (verbose)
169    printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
170
171  memcpy (mem, (void *) fdesc.code, MAX_FUNC_SIZE);
172  mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
173	    2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
174  flush_cache (mem, MAX_FUNC_SIZE);
175
176  signal (SIGSEGV, sighandler);
177
178  /* register the new function: */
179  region = alloca (_U_dyn_region_info_size (2));
180  region->next = NULL;
181  region->insn_count = 3 * (MAX_FUNC_SIZE / 16);
182  region->op_count = 2;
183  _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
184  _U_dyn_op_stop (&region->op[1]);
185
186  memset (&di, 0, sizeof (di));
187  di.start_ip = (long) mem;
188  di.end_ip = (long) mem + 16*region->insn_count/3;
189  di.gp = get_gp (fdesc);
190  di.format = UNW_INFO_FORMAT_DYNAMIC;
191  di.u.pi.name_ptr = (unw_word_t) "copy_of_template";
192  di.u.pi.regions = region;
193
194  _U_dyn_register (&di);
195
196  /* call new function: */
197  fdesc.code = (long) mem;
198  funcp = get_funcp (fdesc);
199
200  if (verbose)
201    (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
202  else
203    (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr);
204
205  _U_dyn_cancel (&di);
206  return -1;
207}
208