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 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 * 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 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