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