15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* libunwind - a platform-independent unwind library 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Copyright (C) 2002-2003 Hewlett-Packard Co 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)This file is part of libunwind. 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Permission is hereby granted, free of charge, to any person obtaining 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)a copy of this software and associated documentation files (the 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)"Software"), to deal in the Software without restriction, including 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)without limitation the rights to use, copy, modify, merge, publish, 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)distribute, sublicense, and/or sell copies of the Software, and to 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)permit persons to whom the Software is furnished to do so, subject to 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)the following conditions: 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)The above copyright notice and this permission notice shall be 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)included in all copies or substantial portions of the Software. 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* This file tests dynamic code-generation via function-cloning. */ 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "flush-cache.h" 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "compiler.h" 315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 325267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <libunwind.h> 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h> 345267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <stdlib.h> 355267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <string.h> 365267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <unistd.h> 375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <signal.h> 383464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch#include <sys/mman.h> 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#if UNW_TARGET_ARM 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define MAX_FUNC_SIZE 96 /* FIXME: arch/compiler dependent */ 425267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#else 435267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#define MAX_FUNC_SIZE 2048 /* max. size of cloned function */ 445267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#endif 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 465267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#define panic(args...) \ 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { fprintf (stderr, args); exit (-1); } 485267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 4906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)typedef void (*template_t) (int, void (*)(), 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int (*)(const char *, ...), const char *, 5106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) const char **); 5206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) 5306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)int verbose; 5406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const char *strarr[] = 5606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) { 573464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL 585267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) }; 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#ifdef __ia64__ 615267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)struct fdesc 625267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) { 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) long code; 643464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch long gp; 655267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) }; 665267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)# define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func)) 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# define get_funcp(fdesc) ((template_t) &(fdesc)) 6851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)# define get_gp(fdesc) ((fdesc).gp) 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#elif __arm__ 705267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)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 84struct 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 93void 94template (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 102static void 103sighandler (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 161int 162dev_null (const char *format UNUSED, ...) 163{ 164 return 0; 165} 166 167int 168main (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