github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-walk.c (about) 1 /* 2 * jit-walk.c - Routines for performing native stack walking. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * 6 * This file is part of the libjit library. 7 * 8 * The libjit library is free software: you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, either version 2.1 of 11 * the License, or (at your option) any later version. 12 * 13 * The libjit library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with the libjit library. If not, see 20 * <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "jit-internal.h" 24 #include "jit-apply-rules.h" 25 26 /* 27 * The routines here are system specific to a large extent, 28 * but we can avoid a lot of the nastiness using gcc builtins. 29 * It is highly recommended that you use gcc to build libjit. 30 * 31 * The following macros may need to be tweaked on some platforms. 32 */ 33 34 /* 35 * Some platforms store the return address in an altered form 36 * (e.g. an offset rather than a pointer). We use this macro to 37 * fix such address values. 38 */ 39 #if defined(__GNUC__) 40 #define jit_fix_return_address(x) (__builtin_extract_return_addr((x))) 41 #else 42 #define jit_fix_return_address(x) (x) 43 #endif 44 45 #if JIT_APPLY_BROKEN_FRAME_BUILTINS == 0 46 47 /* 48 * Extract the next frame pointer in the chain. 49 */ 50 #define jit_next_frame_pointer(x) \ 51 (*((void **)(((unsigned char *)(x)) + JIT_APPLY_PARENT_FRAME_OFFSET))) 52 53 /* 54 * Extract the return address from a particular frame. 55 */ 56 #define jit_extract_return_address(x) \ 57 (*((void **)(((unsigned char *)(x)) + JIT_APPLY_RETURN_ADDRESS_OFFSET))) 58 59 #else /* JIT_APPLY_BROKEN_FRAME_BUILTINS */ 60 61 /* 62 * Extract the next frame pointer in the chain. 63 */ 64 #define jit_next_frame_pointer(x) 0 65 66 /* 67 * Extract the return address from a particular frame. 68 */ 69 #define jit_extract_return_address(x) 0 70 71 #endif /* JIT_APPLY_BROKEN_FRAME_BUILTINS */ 72 73 /* 74 * Fetch the starting frame address if the caller did not supply it 75 * (probably because the caller wasn't compiled with gcc). The address 76 * that we want is actually one frame out from where we are at the moment. 77 * 78 * Note: some gcc vestions have broken __builtin_frame_address() so use 79 * _JIT_ARCH_GET_CURRENT_FRAME() if available. 80 */ 81 #if defined(__GNUC__) 82 #if defined(_JIT_ARCH_GET_CURRENT_FRAME) 83 #define jit_get_starting_frame() \ 84 do { \ 85 _JIT_ARCH_GET_CURRENT_FRAME(start); \ 86 if(start) \ 87 { \ 88 start = jit_next_frame_pointer(start); \ 89 } \ 90 } while (0) 91 #else 92 #define jit_get_starting_frame() \ 93 do { \ 94 start = __builtin_frame_address(0); \ 95 if(start) \ 96 { \ 97 start = jit_next_frame_pointer(start); \ 98 } \ 99 } while (0) 100 #endif 101 #elif defined(_MSC_VER) && defined(_M_IX86) 102 #define jit_get_starting_frame() \ 103 __asm \ 104 { \ 105 __asm mov eax, [ebp] \ 106 __asm mov dword ptr start, eax \ 107 } 108 #else 109 #define jit_get_starting_frame() do { ; } while (0) 110 #endif 111 112 /*@ 113 114 @section Stack walking 115 @cindex Stack walking 116 @cindex jit-walk.h 117 118 The functions in @code{<jit/jit-walk.h>} allow the caller to walk 119 up the native execution stack, inspecting frames and return addresses. 120 121 @*/ 122 123 /*@ 124 * @deftypefun {void *} jit_get_frame_address (unsigned int @var{n}) 125 * Get the frame address for the call frame @var{n} levels up 126 * the stack. Setting @var{n} to zero will retrieve the frame 127 * address for the current function. Returns NULL if it isn't 128 * possible to retrieve the address of the specified frame. 129 * @end deftypefun 130 * 131 * @deftypefun {void *} jit_get_current_frame (void) 132 * Get the frame address for the current function. This may be more 133 * efficient on some platforms than using @code{jit_get_frame_address(0)}. 134 * Returns NULL if it isn't possible to retrieve the address of 135 * the current frame. 136 * @end deftypefun 137 @*/ 138 void *_jit_get_frame_address(void *start, unsigned int n) 139 { 140 /* Fetch the starting frame address if the caller did not supply it */ 141 if(!start) 142 { 143 jit_get_starting_frame(); 144 } 145 146 /* Scan up the stack until we find the frame we want */ 147 while(start != 0 && n > 0) 148 { 149 start = jit_next_frame_pointer(start); 150 --n; 151 } 152 return start; 153 } 154 155 /*@ 156 * @deftypefun {void *} jit_get_next_frame_address (void *@var{frame}) 157 * Get the address of the next frame up the stack from @var{frame}. 158 * Returns NULL if it isn't possible to retrieve the address of 159 * the next frame up the stack. 160 * @end deftypefun 161 @*/ 162 void *_jit_get_next_frame_address(void *frame) 163 { 164 if(frame) 165 { 166 return jit_next_frame_pointer(frame); 167 } 168 else 169 { 170 return 0; 171 } 172 } 173 174 /*@ 175 * @deftypefun {void *} jit_get_return_address (void *@var{frame}) 176 * Get the return address from a specified frame. The address 177 * represents the place where execution returns to when the 178 * specified frame exits. Returns NULL if it isn't possible 179 * to retrieve the return address of the specified frame. 180 * @end deftypefun 181 * 182 * @deftypefun {void *} jit_get_current_return (void) 183 * Get the return address for the current function. This may be more 184 * efficient on some platforms than using @code{jit_get_return_address(0)}. 185 * Returns NULL if it isn't possible to retrieve the return address of 186 * the current frame. 187 * @end deftypefun 188 @*/ 189 void *_jit_get_return_address(void *frame, void *frame0, void *return0) 190 { 191 /* If the caller was compiled with gcc, it may have already figured 192 out the return address for us using builtin gcc facilities */ 193 if(frame && frame == frame0) 194 { 195 return jit_fix_return_address(return0); 196 } 197 else if(frame) 198 { 199 return jit_fix_return_address(jit_extract_return_address(frame)); 200 } 201 else 202 { 203 return 0; 204 } 205 } 206 207 /*@ 208 * @deftypefun int jit_frame_contains_crawl_mark (void *@var{frame}, jit_crawl_mark_t *@var{mark}) 209 * Determine if the stack frame that resides just above @var{frame} 210 * contains a local variable whose address is @var{mark}. The @var{mark} 211 * parameter should be the address of a local variable that is declared with 212 * @code{jit_declare_crawl_mark(@var{name})}. 213 * 214 * Crawl marks are used internally by libjit to determine where control 215 * passes between JIT'ed and ordinary code during an exception throw. 216 * They can also be used to mark frames that have special security 217 * conditions associated with them. 218 * @end deftypefun 219 @*/ 220 int jit_frame_contains_crawl_mark(void *frame, jit_crawl_mark_t *mark) 221 { 222 void *markptr = (void *)mark; 223 void *next; 224 if(!frame) 225 { 226 /* We don't have a frame to check against */ 227 return 0; 228 } 229 next = jit_next_frame_pointer(frame); 230 if(!next) 231 { 232 /* We are at the top of the stack crawl */ 233 return 0; 234 } 235 if(frame <= next) 236 { 237 /* The stack grows downwards in memory */ 238 return (markptr >= frame && markptr < next); 239 } 240 else 241 { 242 /* The stack grows upwards in memory */ 243 return (markptr >= next && markptr < frame); 244 } 245 }