You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

229 lines
6.4 KiB

/*
* jit-walk.c - Routines for performing native stack walking.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "jit-internal.h"
#include "jit-apply-rules.h"
/*
* The routines here are system specific to a large extent,
* but we can avoid a lot of the nastiness using gcc builtins.
* It is highly recommended that you use gcc to build libjit.
*
* The following macros may need to be tweaked on some platforms.
*/
/*
* Some platforms store the return address in an altered form
* (e.g. an offset rather than a pointer). We use this macro to
* fix such address values.
*/
#if defined(__GNUC__)
#define jit_fix_return_address(x) (__builtin_extract_return_addr((x)))
#else
#define jit_fix_return_address(x) (x)
#endif
#if JIT_APPLY_BROKEN_FRAME_BUILTINS == 0
/*
* Extract the next frame pointer in the chain.
*/
#define jit_next_frame_pointer(x) \
(*((void **)(((unsigned char *)(x)) + JIT_APPLY_PARENT_FRAME_OFFSET)))
/*
* Extract the return address from a particular frame.
*/
#define jit_extract_return_address(x) \
(*((void **)(((unsigned char *)(x)) + JIT_APPLY_RETURN_ADDRESS_OFFSET)))
#else /* JIT_APPLY_BROKEN_FRAME_BUILTINS */
/*
* Extract the next frame pointer in the chain.
*/
#define jit_next_frame_pointer(x) 0
/*
* Extract the return address from a particular frame.
*/
#define jit_extract_return_address(x) 0
#endif /* JIT_APPLY_BROKEN_FRAME_BUILTINS */
/*
* Fetch the starting frame address if the caller did not supply it
* (probably because the caller wasn't compiled with gcc). The address
* that we want is actually one frame out from where we are at the moment.
*/
#if defined(__GNUC__)
#define jit_get_starting_frame() \
do { \
start = __builtin_frame_address(0); \
if(start) \
{ \
start = jit_next_frame_pointer(start); \
} \
} while (0)
#elif defined(_MSC_VER) && defined(_M_IX86)
#define jit_get_starting_frame() \
__asm \
{ \
__asm mov eax, [ebp] \
__asm mov dword ptr start, eax \
}
#else
#define jit_get_starting_frame() do { ; } while (0)
#endif
/*@
@section Stack walking
@cindex Stack walking
@cindex jit-walk.h
The functions in @code{<jit/jit-walk.h>} allow the caller to walk
up the native execution stack, inspecting frames and return addresses.
@*/
/*@
* @deftypefun {void *} jit_get_frame_address (unsigned int n)
* Get the frame address for the call frame @code{n} levels up
* the stack. Setting @code{n} to zero will retrieve the frame
* address for the current function. Returns NULL if it isn't
* possible to retrieve the address of the specified frame.
* @end deftypefun
*
* @deftypefun {void *} jit_get_current_frame (void)
* Get the frame address for the current function. This may be more
* efficient on some platforms than using @code{jit_get_frame_address(0)}.
* Returns NULL if it isn't possible to retrieve the address of
* the current frame.
* @end deftypefun
@*/
void *_jit_get_frame_address(void *start, unsigned int n)
{
/* Fetch the starting frame address if the caller did not supply it */
if(!start)
{
jit_get_starting_frame();
}
/* Scan up the stack until we find the frame we want */
while(start != 0 && n > 0)
{
start = jit_next_frame_pointer(start);
--n;
}
return start;
}
/*@
* @deftypefun {void *} jit_get_next_frame_address ({void *} frame)
* Get the address of the next frame up the stack from @code{frame}.
* Returns NULL if it isn't possible to retrieve the address of
* the next frame up the stack.
* @end deftypefun
@*/
void *jit_get_next_frame_address(void *frame)
{
if(frame)
{
return jit_next_frame_pointer(frame);
}
else
{
return 0;
}
}
/*@
* @deftypefun {void *} jit_get_return_address ({void *} frame)
* Get the return address from a specified frame. The address
* represents the place where execution returns to when the
* specified frame exits. Returns NULL if it isn't possible
* to retrieve the return address of the specified frame.
* @end deftypefun
*
* @deftypefun {void *} jit_get_current_return (void)
* Get the return address for the current function. This may be more
* efficient on some platforms than using @code{jit_get_return_address(0)}.
* Returns NULL if it isn't possible to retrieve the return address of
* the current frame.
* @end deftypefun
@*/
void *_jit_get_return_address(void *frame, void *frame0, void *return0)
{
/* If the caller was compiled with gcc, it may have already figured
out the return address for us using builtin gcc facilities */
if(frame && frame == frame0)
{
return jit_fix_return_address(return0);
}
else if(frame)
{
return jit_fix_return_address(jit_extract_return_address(frame));
}
else
{
return 0;
}
}
/*@
* @deftypefun int jit_frame_contains_crawl_mark ({void *}frame, {jit_crawl_mark_t *} mark)
* Determine if the stack frame that resides just above @code{frame}
* contains a local variable whose address is @code{mark}. The @code{mark}
* parameter should be the address of a local variable that is declared with
* @code{jit_declare_crawl_mark(name)}.
*
* Crawl marks are used internally by libjit to determine where control
* passes between JIT'ed and ordinary code during an exception throw.
* They can also be used to mark frames that have special security
* conditions associated with them.
* @end deftypefun
@*/
int jit_frame_contains_crawl_mark(void *frame, jit_crawl_mark_t *mark)
{
void *markptr = (void *)mark;
void *next;
if(!frame)
{
/* We don't have a frame to check against */
return 0;
}
next = jit_next_frame_pointer(frame);
if(!next)
{
/* We are at the top of the stack crawl */
return 0;
}
if(frame <= next)
{
/* The stack grows downwards in memory */
return (markptr >= frame && markptr < next);
}
else
{
/* The stack grows upwards in memory */
return (markptr >= next && markptr < frame);
}
}