Gtest-dyn1.c revision 39b83981594d2e49a83e4aaedcab8395c01ddd03
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 <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33#include <signal.h> 34#include <sys/mman.h> 35 36#if UNW_TARGET_ARM 37#define MAX_FUNC_SIZE 96 /* FIXME: arch/compiler dependent */ 38#else 39#define MAX_FUNC_SIZE 2048 /* max. size of cloned function */ 40#endif 41 42#define panic(args...) \ 43 { fprintf (stderr, args); exit (-1); } 44 45typedef void (*template_t) (int, void (*)(), 46 int (*)(const char *, ...), const char *, 47 const char **); 48 49int verbose; 50 51static const char *strarr[] = 52 { 53 "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL 54 }; 55 56#ifdef __ia64__ 57struct fdesc 58 { 59 long code; 60 long gp; 61 }; 62# define get_fdesc(fdesc,func) (fdesc = *(struct fdesc *) &(func)) 63# define get_funcp(fdesc) ((template_t) &(fdesc)) 64# define get_gp(fdesc) ((fdesc).gp) 65#elif __arm__ 66struct fdesc 67 { 68 long code; 69 long is_thumb; 70 }; 71/* Workaround GCC bug: https://bugs.launchpad.net/gcc-linaro/+bug/721531 */ 72# define get_fdesc(fdesc,func) ({long tmp = (long) &(func); \ 73 (fdesc).code = (long) &(func) & ~0x1; \ 74 (fdesc).is_thumb = tmp & 0x1;}) 75/*# define get_fdesc(fdesc,func) ({(fdesc).code = (long) &(func) & ~0x1; \ 76 (fdesc).is_thumb = (long) &(func) & 0x1;})*/ 77# define get_funcp(fdesc) ((template_t) ((fdesc).code | (fdesc).is_thumb)) 78# define get_gp(fdesc) (0) 79#else 80struct fdesc 81 { 82 long code; 83 }; 84# define get_fdesc(fdesc,func) (fdesc.code = (long) &(func)) 85# define get_funcp(fdesc) ((template_t) (fdesc).code) 86# define get_gp(fdesc) (0) 87#endif 88 89#ifndef __GNUC__ 90extern void flush_cache (void *addr, size_t len); 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 __attribute__((unused)), ...) 163{ 164 return 0; 165} 166 167int 168main (int argc, char *argv[] __attribute__((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#ifdef __GNUC__ 191 __builtin___clear_cache(mem, mem + MAX_FUNC_SIZE); 192#else 193 flush_cache (mem, MAX_FUNC_SIZE); 194#endif 195 196 signal (SIGSEGV, sighandler); 197 198 /* register the new function: */ 199 region = alloca (_U_dyn_region_info_size (2)); 200 region->next = NULL; 201 region->insn_count = 3 * (MAX_FUNC_SIZE / 16); 202 region->op_count = 2; 203 _U_dyn_op_alias (®ion->op[0], 0, -1, fdesc.code); 204 _U_dyn_op_stop (®ion->op[1]); 205 206 memset (&di, 0, sizeof (di)); 207 di.start_ip = (long) mem; 208 di.end_ip = (long) mem + 16*region->insn_count/3; 209 di.gp = get_gp (fdesc); 210 di.format = UNW_INFO_FORMAT_DYNAMIC; 211 di.u.pi.name_ptr = (unw_word_t) "copy_of_template"; 212 di.u.pi.regions = region; 213 214 _U_dyn_register (&di); 215 216 /* call new function: */ 217 fdesc.code = (long) mem; 218 funcp = get_funcp (fdesc); 219 220 if (verbose) 221 (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr); 222 else 223 (*funcp) (10, funcp, dev_null, "iteration %c%s\n", strarr); 224 225 _U_dyn_cancel (&di); 226 return -1; 227} 228