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 
13 int 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 
25 int
make_executable(void * addr,size_t len)26 make_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 
38 void *
create_func(unw_dyn_info_t * di,const char * name,long (* func)(),void * end,unw_dyn_region_info_t * region)39 create_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 
84 int
main(int argc,char ** argv)85 main (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