You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
6.0 KiB
223 lines
6.0 KiB
#include "flush-cache.h" |
|
|
|
#include <assert.h> |
|
#include <libunwind.h> |
|
#include <unistd.h> |
|
#include <signal.h> |
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
|
|
#include <sys/mman.h> |
|
|
|
int verbose; |
|
|
|
#ifdef __ia64__ |
|
# define GET_ENTRY(fdesc) (((uintptr_t *) (fdesc))[0]) |
|
# define GET_GP(fdesc) (((uintptr_t *) (fdesc))[0]) |
|
# define EXTRA 16 |
|
#else |
|
# define GET_ENTRY(fdesc) ((uintptr_t ) (fdesc)) |
|
# define GET_GP(fdesc) (0) |
|
# define EXTRA 0 |
|
#endif |
|
|
|
int |
|
make_executable (void *addr, size_t len) |
|
{ |
|
if (mprotect ((void *) (((long) addr) & -getpagesize ()), len, |
|
PROT_READ | PROT_WRITE | PROT_EXEC) < 0) |
|
{ |
|
perror ("mprotect"); |
|
return -1; |
|
} |
|
flush_cache (addr, len); |
|
return 0; |
|
} |
|
|
|
void * |
|
create_func (unw_dyn_info_t *di, const char *name, long (*func) (), |
|
void *end, unw_dyn_region_info_t *region) |
|
{ |
|
void *mem, *memend, *addr, *fptr; |
|
unw_word_t gp = 0; |
|
size_t len; |
|
|
|
len = (uintptr_t) end - GET_ENTRY (func) + EXTRA; |
|
mem = malloc (len); |
|
if (verbose) |
|
printf ("%s: cloning %s at %p (%zu bytes)\n", |
|
__FUNCTION__, name, mem, len); |
|
memend = (char *) mem + len; |
|
|
|
#ifdef __ia64__ |
|
addr = (void *) GET_ENTRY (func); |
|
|
|
/* build function descriptor: */ |
|
((long *) mem)[0] = (long) mem + 16; /* entry point */ |
|
((long *) mem)[1] = GET_GP (func); /* global-pointer */ |
|
fptr = mem; |
|
mem = (void *) ((long) mem + 16); |
|
#else |
|
fptr = mem; |
|
#endif |
|
|
|
len = (char *) memend - (char *) mem; |
|
memcpy (mem, addr, len); |
|
|
|
if (make_executable (mem, len) < 0) |
|
return NULL; |
|
|
|
if (di) |
|
{ |
|
memset (di, 0, sizeof (*di)); |
|
di->start_ip = (unw_word_t) mem; |
|
di->end_ip = (unw_word_t) memend; |
|
di->gp = gp; |
|
di->format = UNW_INFO_FORMAT_DYNAMIC; |
|
di->u.pi.name_ptr = (unw_word_t) name; |
|
di->u.pi.regions = region; |
|
} |
|
return fptr; |
|
} |
|
|
|
int |
|
main (int argc, char **argv) |
|
{ |
|
extern long func_add1 (long); |
|
extern char func_add1_end[]; |
|
extern long func_add3 (long, long (*[])()); |
|
extern char func_add3_end[]; |
|
extern long func_vframe (long); |
|
extern char func_vframe_end[]; |
|
unw_dyn_region_info_t *r_pro, *r_epi, *r, *rtmp; |
|
unw_dyn_info_t di0, di1, di2, di3; |
|
long (*add1) (long); |
|
long (*add3_0) (long); |
|
long (*add3_1) (long, void *[]); |
|
long (*vframe) (long); |
|
void *flist[2]; |
|
long ret; |
|
int i; |
|
|
|
signal (SIGUSR1, SIG_IGN); |
|
signal (SIGUSR2, SIG_IGN); |
|
|
|
if (argc != 1) |
|
verbose = 1; |
|
|
|
add1 = (long (*)(long)) |
|
create_func (&di0, "func_add1", func_add1, func_add1_end, NULL); |
|
|
|
/* Describe the epilogue of func_add3: */ |
|
i = 0; |
|
r_epi = alloca (_U_dyn_region_info_size (5)); |
|
r_epi->op_count = 5; |
|
r_epi->next = NULL; |
|
r_epi->insn_count = -9; |
|
_U_dyn_op_pop_frames (&r_epi->op[i++], |
|
_U_QP_TRUE, /* when=*/ 5, /* num_frames=*/ 1); |
|
_U_dyn_op_stop (&r_epi->op[i++]); |
|
assert ((unsigned) i <= r_epi->op_count); |
|
|
|
/* Describe the prologue of func_add3: */ |
|
i = 0; |
|
r_pro = alloca (_U_dyn_region_info_size (4)); |
|
r_pro->op_count = 4; |
|
r_pro->next = r_epi; |
|
r_pro->insn_count = 8; |
|
_U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 0, |
|
/* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + 34); |
|
_U_dyn_op_add (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 2, |
|
/* reg= */ UNW_IA64_SP, /* val=*/ -16); |
|
_U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 4, |
|
/* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3); |
|
_U_dyn_op_spill_sp_rel (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 7, |
|
/* reg=*/ UNW_IA64_RP, /* off=*/ 16); |
|
assert ((unsigned) i <= r_pro->op_count); |
|
|
|
/* Create regions for func_vframe: */ |
|
i = 0; |
|
r = alloca (_U_dyn_region_info_size (16)); |
|
r->op_count = 16; |
|
r->next = NULL; |
|
r->insn_count = 4; |
|
_U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402); |
|
_U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 3, /* frames=*/ 1); |
|
_U_dyn_op_stop (&r->op[i++]); |
|
assert ((unsigned) i <= r->op_count); |
|
|
|
i = 0; |
|
rtmp = r; |
|
r = alloca (_U_dyn_region_info_size (16)); |
|
r->op_count = 16; |
|
r->next = rtmp; |
|
r->insn_count = 16; |
|
_U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 8, |
|
/* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 3); |
|
_U_dyn_op_pop_frames (&r->op[i++], _U_QP_TRUE, /* when=*/ 10, |
|
/* num_frames=*/ 1); |
|
_U_dyn_op_stop (&r->op[i++]); |
|
assert ((unsigned) i <= r->op_count); |
|
|
|
i = 0; |
|
rtmp = r; |
|
r = alloca (_U_dyn_region_info_size (16)); |
|
r->op_count = 16; |
|
r->next = rtmp; |
|
r->insn_count = 5; |
|
_U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 1, |
|
/* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + 33); |
|
_U_dyn_op_save_reg (&r->op[i++], _U_QP_TRUE, /* when=*/ 2, |
|
/* reg=*/ UNW_IA64_SP, /* dst=*/ UNW_IA64_GR + 34); |
|
_U_dyn_op_spill_fp_rel (&r->op[i++], _U_QP_TRUE, /* when=*/ 4, |
|
/* reg=*/ UNW_IA64_AR_PFS, /* off=*/ 16); |
|
_U_dyn_op_label_state (&r->op[i++], /* label=*/ 100402); |
|
_U_dyn_op_stop (&r->op[i++]); |
|
assert ((unsigned) i <= r->op_count); |
|
|
|
/* Create two functions which can share the region-list: */ |
|
add3_0 = (long (*) (long)) |
|
create_func (&di1, "func_add3/0", func_add3, func_add3_end, r_pro); |
|
add3_1 = (long (*) (long, void *[])) |
|
create_func (&di2, "func_add3/1", func_add3, func_add3_end, r_pro); |
|
vframe = (long (*) (long)) |
|
create_func (&di3, "func_vframe", func_vframe, func_vframe_end, r); |
|
|
|
_U_dyn_register (&di1); |
|
_U_dyn_register (&di2); |
|
_U_dyn_register (&di3); |
|
_U_dyn_register (&di0); |
|
|
|
flist[0] = add3_0; |
|
flist[1] = add1; |
|
|
|
kill (getpid (), SIGUSR1); /* do something ptmon can latch onto */ |
|
ret = (*add3_1) (13, flist); |
|
if (ret != 18) |
|
{ |
|
fprintf (stderr, "FAILURE: (*add3_1)(13) returned %ld\n", ret); |
|
exit (-1); |
|
} |
|
|
|
ret = (*vframe) (48); |
|
if (ret != 4) |
|
{ |
|
fprintf (stderr, "FAILURE: (*vframe)(16) returned %ld\n", ret); |
|
exit (-1); |
|
} |
|
ret = (*vframe) (64); |
|
if (ret != 10) |
|
{ |
|
fprintf (stderr, "FAILURE: (*vframe)(32) returned %ld\n", ret); |
|
exit (-1); |
|
} |
|
kill (getpid (), SIGUSR2); /* do something ptmon can latch onto */ |
|
|
|
_U_dyn_cancel (&di0); |
|
_U_dyn_cancel (&di1); |
|
_U_dyn_cancel (&di3); |
|
_U_dyn_cancel (&di2); |
|
|
|
return 0; |
|
}
|
|
|