1#include "flush-cache.h"
2
3#include <assert.h>
4#include <libunwind.h>
5#include <unistd.h>
6#include <signal.h>
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10
11#include <sys/mman.h>
12
13int verbose;
14
15#ifdef __ia64__
16# define GET_ENTRY(fdesc)	(((uintptr_t *) (fdesc))[0])
17# define GET_GP(fdesc)		(((uintptr_t *) (fdesc))[0])
18# define EXTRA			16
19#else
20# define GET_ENTRY(fdesc)	((uintptr_t ) (fdesc))
21# define GET_GP(fdesc)		(0)
22# define EXTRA			0
23#endif
24
25int
26make_executable (void *addr, size_t len)
27{
28  if (mprotect ((void *) (((long) addr) & -getpagesize ()), len,
29		PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
30    {
31      perror ("mprotect");
32      return -1;
33    }
34  flush_cache (addr, len);
35  return 0;
36}
37
38void *
39create_func (unw_dyn_info_t *di, const char *name, long (*func) (),
40	     void *end, unw_dyn_region_info_t *region)
41{
42  void *mem, *memend, *addr, *fptr;
43  unw_word_t gp = 0;
44  size_t len;
45
46  len = (uintptr_t) end - GET_ENTRY (func) + EXTRA;
47  mem = malloc (len);
48  if (verbose)
49    printf ("%s: cloning %s at %p (%zu bytes)\n",
50	    __FUNCTION__, name, mem, len);
51  memend = (char *) mem + len;
52
53#ifdef __ia64__
54  addr = (void *) GET_ENTRY (func);
55
56  /* build function descriptor: */
57  ((long *) mem)[0] = (long) mem + 16;		/* entry point */
58  ((long *) mem)[1] = GET_GP (func);		/* global-pointer */
59  fptr = mem;
60  mem = (void *) ((long) mem + 16);
61#else
62  fptr = mem;
63#endif
64
65  len = (char *) memend - (char *) mem;
66  memcpy (mem, addr, len);
67
68  if (make_executable (mem, len) < 0)
69    return NULL;
70
71  if (di)
72    {
73      memset (di, 0, sizeof (*di));
74      di->start_ip = (unw_word_t) mem;
75      di->end_ip = (unw_word_t) memend;
76      di->gp = gp;
77      di->format = UNW_INFO_FORMAT_DYNAMIC;
78      di->u.pi.name_ptr = (unw_word_t) name;
79      di->u.pi.regions = region;
80    }
81  return fptr;
82}
83
84int
85main (int argc, char **argv)
86{
87  extern long func_add1 (long);
88  extern char func_add1_end[];
89  extern long func_add3 (long, long (*[])());
90  extern char func_add3_end[];
91  extern long func_vframe (long);
92  extern char func_vframe_end[];
93  unw_dyn_region_info_t *r_pro, *r_epi, *r, *rtmp;
94  unw_dyn_info_t di0, di1, di2, di3;
95  long (*add1) (long);
96  long (*add3_0) (long);
97  long (*add3_1) (long, void *[]);
98  long (*vframe) (long);
99  void *flist[2];
100  long ret;
101  int i;
102
103  signal (SIGUSR1, SIG_IGN);
104  signal (SIGUSR2, SIG_IGN);
105
106  if (argc != 1)
107    verbose = 1;
108
109  add1 = (long (*)(long))
110	  create_func (&di0, "func_add1", func_add1, func_add1_end, NULL);
111
112  /* Describe the epilogue of func_add3: */
113  i = 0;
114  r_epi = alloca (_U_dyn_region_info_size (5));
115  r_epi->op_count = 5;
116  r_epi->next = NULL;
117  r_epi->insn_count = -9;
118  _U_dyn_op_pop_frames (&r_epi->op[i++],
119			_U_QP_TRUE, /* when=*/ 5, /* num_frames=*/ 1);
120  _U_dyn_op_stop (&r_epi->op[i++]);
121  assert ((unsigned) i <= r_epi->op_count);
122
123  /* Describe the prologue of func_add3: */
124  i = 0;
125  r_pro = alloca (_U_dyn_region_info_size (4));
126  r_pro->op_count = 4;
127  r_pro->next = r_epi;
128  r_pro->insn_count = 8;
129  _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 0,
130		      /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + 34);
131  _U_dyn_op_add (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 2,
132		 /* reg= */ UNW_IA64_SP, /* val=*/ -16);
133  _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 4,
134		      /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3);
135  _U_dyn_op_spill_sp_rel (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 7,
136		      /* reg=*/ UNW_IA64_RP, /* off=*/ 16);
137  assert ((unsigned) i <= r_pro->op_count);
138
139  /* Create regions for func_vframe: */
140  i = 0;
141  r = alloca (_U_dyn_region_info_size (16));
142  r->op_count = 16;
143  r->next = NULL;
144  r->insn_count = 4;
145  _U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402);
146  _U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 3, /* frames=*/ 1);
147  _U_dyn_op_stop (&r->op[i++]);
148  assert ((unsigned) i <= r->op_count);
149
150  i = 0;
151  rtmp = r;
152  r = alloca (_U_dyn_region_info_size (16));
153  r->op_count = 16;
154  r->next = rtmp;
155  r->insn_count = 16;
156  _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 8,
157		      /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3);
158  _U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 10,
159			/* num_frames=*/ 1);
160  _U_dyn_op_stop (&r->op[i++]);
161  assert ((unsigned) i <= r->op_count);
162
163  i = 0;
164  rtmp = r;
165  r = alloca (_U_dyn_region_info_size (16));
166  r->op_count = 16;
167  r->next = rtmp;
168  r->insn_count = 5;
169  _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 1,
170			  /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 33);
171  _U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 2,
172			  /* reg=*/ UNW_IA64_SP, /* dst=*/ UNW_IA64_GR + 34);
173  _U_dyn_op_spill_fp_rel (&r->op[i++], _U_QP_TRUE, /* when=*/ 4,
174			  /* reg=*/ UNW_IA64_AR_PFS, /* off=*/ 16);
175  _U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402);
176  _U_dyn_op_stop (&r->op[i++]);
177  assert ((unsigned) i <= r->op_count);
178
179  /* Create two functions which can share the region-list:  */
180  add3_0 = (long (*) (long))
181	  create_func (&di1, "func_add3/0", func_add3, func_add3_end, r_pro);
182  add3_1 = (long (*) (long, void *[]))
183	  create_func (&di2, "func_add3/1", func_add3, func_add3_end, r_pro);
184  vframe = (long (*) (long))
185	  create_func (&di3, "func_vframe", func_vframe, func_vframe_end, r);
186
187  _U_dyn_register (&di1);
188  _U_dyn_register (&di2);
189  _U_dyn_register (&di3);
190  _U_dyn_register (&di0);
191
192  flist[0] = add3_0;
193  flist[1] = add1;
194
195  kill (getpid (), SIGUSR1);	/* do something ptmon can latch onto */
196  ret = (*add3_1) (13, flist);
197  if (ret != 18)
198    {
199      fprintf (stderr, "FAILURE: (*add3_1)(13) returned %ld\n", ret);
200      exit (-1);
201    }
202
203  ret = (*vframe) (48);
204  if (ret != 4)
205    {
206      fprintf (stderr, "FAILURE: (*vframe)(16) returned %ld\n", ret);
207      exit (-1);
208    }
209  ret = (*vframe) (64);
210  if (ret != 10)
211    {
212      fprintf (stderr, "FAILURE: (*vframe)(32) returned %ld\n", ret);
213      exit (-1);
214    }
215  kill (getpid (), SIGUSR2);	/* do something ptmon can latch onto */
216
217  _U_dyn_cancel (&di0);
218  _U_dyn_cancel (&di1);
219  _U_dyn_cancel (&di3);
220  _U_dyn_cancel (&di2);
221
222  return 0;
223}
224