Home | History | Annotate | Download | only in tests
      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