Gtest-dyn1.c revision 570c09a2afe255ce30b64e3298218ffbcff73e80
1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2002-2003 Hewlett-Packard Co 3 Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4 5This file is part of libunwind. 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be 16included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25 26/* This file tests dynamic code-generation via function-cloning. */ 27 28#include <libunwind.h> 29#include <malloc.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <unistd.h> 34 35#include <sys/mman.h> 36 37#if UNW_TARGET_ARM 38#define MAX_FUNC_SIZE 96 /* FIXME: arch/compiler dependent */ 39#else 40#define MAX_FUNC_SIZE 2048 /* max. size of cloned function */ 41#endif 42 43#define panic(args...) \ 44 { fprintf (stderr, args); exit (-1); } 45 46typedef void (*template_t) (int, void (*)(), 47 int (*)(const char *, ...), const char *, 48 const char **); 49 50int verbose; 51 52static const char *strarr[] = 53 { 54 "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL 55 }; 56 57#ifdef __ia64__ 58struct fdesc 59 { 60 long code; 61 long gp; 62 }; 63# define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func)) 64# define get_funcp(fdesc) ((template_t) &(fdesc)) 65# define get_gp(fdesc) ((fdesc).gp) 66#else 67struct fdesc 68 { 69 long code; 70 }; 71# define get_fdesc(fdesc,func) (fdesc.code = (long) &(func)) 72# define get_funcp(fdesc) ((template_t) (fdesc).code) 73# define get_gp(fdesc) (0) 74#endif 75 76extern void flush_cache (void *addr, size_t len); 77 78void 79template (int i, template_t self, 80 int (*printer)(const char *, ...), const char *fmt, const char **arr) 81{ 82 (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1); 83 if (i > 0) 84 (*self) (i - 1, self, printer, fmt, arr); 85} 86 87static void 88sighandler (int signal) 89{ 90 unw_cursor_t cursor; 91 char name[128], off[32]; 92 unw_word_t ip, offset; 93 unw_context_t uc; 94 int count; 95 96 if (verbose) 97 printf ("caught signal %d\n", signal); 98 99 unw_getcontext (&uc); 100 unw_init_local (&cursor, &uc); 101 102 count = 0; 103 while (!unw_is_signal_frame (&cursor)) 104 { 105 if (unw_step (&cursor) < 0) 106 panic ("failed to find signal frame!\n"); 107 108 if (count++ > 20) 109 { 110 panic ("Too many steps to the signal frame (%d)\n", count); 111 break; 112 } 113 } 114 unw_step (&cursor); 115 116 count = 0; 117 do 118 { 119 unw_get_reg (&cursor, UNW_REG_IP, &ip); 120 name[0] = '\0'; 121 off[0] = '\0'; 122 if (unw_get_proc_name (&cursor, name, sizeof (name), &offset) == 0 123 && offset > 0) 124 snprintf (off, sizeof (off), "+0x%lx", (long) offset); 125 if (verbose) 126 printf ("ip = %lx <%s%s>\n", (long) ip, name, off); 127 ++count; 128 129 if (count > 20) 130 { 131 panic ("Too many steps (%d)\n", count); 132 break; 133 } 134 135 } 136 while (unw_step (&cursor) > 0); 137 138 if (count != 13) 139 panic ("FAILURE: expected 13, not %d frames below signal frame\n", count); 140 141 if (verbose) 142 printf ("SUCCESS\n"); 143 exit (0); 144} 145 146int 147dev_null (const char *format, ...) 148{ 149 return 0; 150} 151 152int 153main (int argc, char *argv[]) 154{ 155 unw_dyn_region_info_t *region; 156 unw_dyn_info_t di; 157 struct fdesc fdesc; 158 template_t funcp; 159 void *mem; 160 161 if (argc > 1) 162 ++verbose; 163 164 mem = malloc (getpagesize ()); 165 166 get_fdesc (fdesc, template); 167 168 if (verbose) 169 printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem); 170 171 memcpy (mem, (void *) fdesc.code, MAX_FUNC_SIZE); 172 mprotect ((void *) ((long) mem & ~(getpagesize () - 1)), 173 2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC); 174 flush_cache (mem, MAX_FUNC_SIZE); 175 176 signal (SIGSEGV, sighandler); 177 178 /* register the new function: */ 179 region = alloca (_U_dyn_region_info_size (2)); 180 region->next = NULL; 181 region->insn_count = 3 * (MAX_FUNC_SIZE / 16); 182 region->op_count = 2; 183 _U_dyn_op_alias (®ion->op[0], 0, -1, fdesc.code); 184 _U_dyn_op_stop (®ion->op[1]); 185 186 memset (&di, 0, sizeof (di)); 187 di.start_ip = (long) mem; 188 di.end_ip = (long) mem + 16*region->insn_count/3; 189 di.gp = get_gp (fdesc); 190 di.format = UNW_INFO_FORMAT_DYNAMIC; 191 di.u.pi.name_ptr = (unw_word_t) "copy_of_template"; 192 di.u.pi.regions = region; 193 194 _U_dyn_register (&di); 195 196 /* call new function: */ 197 fdesc.code = (long) mem; 198 funcp = get_funcp (fdesc); 199 200 if (verbose) 201 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr); 202 else 203 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr); 204 205 _U_dyn_cancel (&di); 206 return -1; 207} 208