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