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  }