mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
Moved Robert's stack tracking code out of m_aspacemgr into a new module
m_stacks, because it's a nicely distinct and stand-alone piece of functionality. This happily removes m_aspacemgr's dependence on m_mallocfree (there was an apparent dependence due to the #include, even if it didn't manifest itself in practice -- very important!) and m_options (not so important). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4009
This commit is contained in:
parent
f3b8c7430e
commit
f4ee5eee2a
@ -63,6 +63,7 @@ noinst_HEADERS = \
|
||||
pub_core_sigframe.h \
|
||||
pub_core_signals.h \
|
||||
pub_core_skiplist.h \
|
||||
pub_core_stacks.h \
|
||||
pub_core_stacktrace.h \
|
||||
pub_core_syswrap.h \
|
||||
pub_core_threadmodel.h \
|
||||
@ -117,6 +118,7 @@ stage2_SOURCES = \
|
||||
m_redir.c \
|
||||
m_signals.c \
|
||||
m_skiplist.c \
|
||||
m_stacks.c \
|
||||
m_stacktrace.c \
|
||||
m_syscall.c \
|
||||
m_threadmodel.c \
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- The address space manager: segment initialisation and ---*/
|
||||
/*--- tracking, stack operations ---*/
|
||||
/*--- aspacemgr.c ---*/
|
||||
/*--- m_aspacemgr.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -38,11 +38,9 @@
|
||||
#include "pub_core_libcfile.h" // For VG_(fstat), VG_(resolve_filename_nodup)
|
||||
#include "pub_core_libcmman.h"
|
||||
#include "pub_core_libcprint.h"
|
||||
#include "pub_core_mallocfree.h"
|
||||
#include "pub_core_options.h"
|
||||
#include "pub_core_syscall.h"
|
||||
#include "pub_core_tooliface.h"
|
||||
#include "pub_core_transtab.h"
|
||||
#include "pub_core_transtab.h" // For VG_(discard_translations)
|
||||
#include "vki_unistd.h"
|
||||
|
||||
|
||||
@ -1070,269 +1068,6 @@ Segment *VG_(find_segment_above_mapped)(Addr a)
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Tracking permissions around %esp changes. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
The stack
|
||||
~~~~~~~~~
|
||||
The stack's segment seems to be dynamically extended downwards by
|
||||
the kernel as the stack pointer moves down. Initially, a 1-page
|
||||
(4k) stack is allocated. When SP moves below that for the first
|
||||
time, presumably a page fault occurs. The kernel detects that the
|
||||
faulting address is in the range from SP - VG_STACK_REDZONE_SZB
|
||||
upwards to the current valid stack. It then extends the stack
|
||||
segment downwards for enough to cover the faulting address, and
|
||||
resumes the process (invisibly). The process is unaware of any of
|
||||
this.
|
||||
|
||||
That means that Valgrind can't spot when the stack segment is being
|
||||
extended. Fortunately, we want to precisely and continuously
|
||||
update stack permissions around SP, so we need to spot all writes
|
||||
to SP anyway.
|
||||
|
||||
The deal is: when SP is assigned a lower value, the stack is being
|
||||
extended. Create suitably-permissioned pages to fill in any holes
|
||||
between the old stack ptr and this one, if necessary. Then mark
|
||||
all bytes in the area just "uncovered" by this SP change as
|
||||
write-only.
|
||||
|
||||
When SP goes back up, mark the area receded over as unreadable and
|
||||
unwritable.
|
||||
|
||||
Just to record the SP boundary conditions somewhere convenient:
|
||||
SP - VG_STACK_REDZONE_SZB always points to the lowest live byte in
|
||||
the stack. All addresses below SP - VG_STACK_REDZONE_SZB are not
|
||||
live; those at and above it are.
|
||||
|
||||
We do not concern ourselves here with the VG_STACK_REDZONE_SZB
|
||||
bias; that is handled by new_mem_stack/die_mem_stack.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This structure holds information about the start and end addresses of
|
||||
* registered stacks. There's always at least one stack registered:
|
||||
* the main process stack. It will be the first stack registered and
|
||||
* so will have a stack id of 0. The user does not need to register
|
||||
* this stack: Valgrind does it automatically right before it starts
|
||||
* running the client. No other stacks are automatically registered by
|
||||
* Valgrind, however.
|
||||
*/
|
||||
|
||||
typedef struct _Stack {
|
||||
UWord id;
|
||||
Addr start;
|
||||
Addr end;
|
||||
struct _Stack *next;
|
||||
} Stack;
|
||||
|
||||
static Stack *stacks;
|
||||
static UWord next_id; /* Next id we hand out to a newly registered stack */
|
||||
|
||||
/*
|
||||
* These are the id, start and end values of the current stack. If the
|
||||
* stack pointer falls outside the range of the current stack, we search
|
||||
* the stacks list above for a matching stack.
|
||||
*/
|
||||
|
||||
static Addr current_stack_start;
|
||||
static Addr current_stack_end;
|
||||
static UWord current_stack_id;
|
||||
|
||||
/* Search for a particular stack by id number. */
|
||||
static Bool find_stack_by_id(UWord id, Addr *start, Addr *end)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
while(i) {
|
||||
if(i->id == id) {
|
||||
*start = i->start;
|
||||
*end = i->end;
|
||||
return True;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Find what stack an address falls into. */
|
||||
static Bool find_stack_by_addr(Addr sp, Addr *start, Addr *end, UWord *id)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
while(i) {
|
||||
if(sp >= i->start && sp <= i->end) {
|
||||
*start = i->start;
|
||||
*end = i->end;
|
||||
*id = i->id;
|
||||
return True;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Change over to a new stack. */
|
||||
static Bool set_current_stack(UWord id)
|
||||
{
|
||||
Addr start, end;
|
||||
if (find_stack_by_id(id, &start, &end)) {
|
||||
current_stack_id = id;
|
||||
current_stack_start = start;
|
||||
current_stack_end = end;
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a new stack from start - end. This is invoked from the
|
||||
* VALGRIND_STACK_REGISTER client request, and is also called just before
|
||||
* we start the client running, to register the main process stack.
|
||||
*
|
||||
* Note: this requires allocating a piece of memory to store the Stack
|
||||
* structure, which places a dependency between this module and the
|
||||
* mallocfree module. However, there is no real chance of a circular
|
||||
* dependency here, since the mallocfree module would never call back to
|
||||
* this function.
|
||||
*/
|
||||
|
||||
UWord VG_(handle_stack_register)(Addr start, Addr end)
|
||||
{
|
||||
Stack *i;
|
||||
if (start > end) {
|
||||
Addr t = end;
|
||||
end = start;
|
||||
start = t;
|
||||
}
|
||||
|
||||
i = (Stack *)VG_(arena_malloc)(VG_AR_CORE, sizeof(Stack));
|
||||
i->start = start;
|
||||
i->end = end;
|
||||
i->id = next_id++;
|
||||
i->next = stacks;
|
||||
stacks = i;
|
||||
|
||||
if(i->id == 0) {
|
||||
set_current_stack(i->id);
|
||||
}
|
||||
|
||||
return i->id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deregister a stack. This is invoked from the VALGRIND_STACK_DEREGISTER
|
||||
* client request.
|
||||
*
|
||||
* Note: this requires freeing the piece of memory that was used to store
|
||||
* the Stack structure, which places a dependency between this module
|
||||
* and the mallocfree module. However, there is no real chance of
|
||||
* a circular dependency here, since the mallocfree module would never
|
||||
* call back to this function.
|
||||
*/
|
||||
|
||||
void VG_(handle_stack_deregister)(UWord id)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
Stack *prev = NULL;
|
||||
|
||||
if(current_stack_id == id) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(i) {
|
||||
if (i->id == id) {
|
||||
if(prev == NULL) {
|
||||
stacks = i->next;
|
||||
} else {
|
||||
prev->next = i->next;
|
||||
}
|
||||
VG_(arena_free)(VG_AR_CORE, i);
|
||||
return;
|
||||
}
|
||||
prev = i;
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change a stack. This is invoked from the VALGRIND_STACK_CHANGE client
|
||||
* request and from the stack growth stuff the signals module when
|
||||
* extending the main process stack.
|
||||
*/
|
||||
|
||||
void VG_(handle_stack_change)(UWord id, Addr start, Addr end)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
|
||||
if (id == current_stack_id) {
|
||||
current_stack_start = start;
|
||||
current_stack_end = end;
|
||||
}
|
||||
|
||||
while(i) {
|
||||
if (i->id == id) {
|
||||
i->start = start;
|
||||
i->end = end;
|
||||
return;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function gets called if new_mem_stack and/or die_mem_stack are
|
||||
tracked by the tool, and one of the specialised cases
|
||||
(eg. new_mem_stack_4) isn't used in preference.
|
||||
*/
|
||||
VG_REGPARM(2)
|
||||
void VG_(unknown_SP_update)( Addr old_SP, Addr new_SP )
|
||||
{
|
||||
static Int moans = 3;
|
||||
Word delta = (Word)new_SP - (Word)old_SP;
|
||||
|
||||
/* Check if the stack pointer is still in the same stack as before. */
|
||||
if (new_SP < current_stack_start || new_SP > current_stack_end) {
|
||||
Addr start, end;
|
||||
UWord new_id;
|
||||
Bool found = find_stack_by_addr(new_SP, &start, &end, &new_id);
|
||||
if (found && new_id != current_stack_id) {
|
||||
/* The stack pointer is now in another stack. Update the current
|
||||
stack information and return without doing anything else. */
|
||||
set_current_stack(new_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (delta < -VG_(clo_max_stackframe) || VG_(clo_max_stackframe) < delta) {
|
||||
/* SP has changed by more than some threshold amount (by
|
||||
default, 2MB). We take this to mean that the application is
|
||||
switching to a new stack, for whatever reason.
|
||||
|
||||
JRS 20021001: following discussions with John Regehr, if a stack
|
||||
switch happens, it seems best not to mess at all with memory
|
||||
permissions. Seems to work well with Netscape 4.X. Really the
|
||||
only remaining difficulty is knowing exactly when a stack switch is
|
||||
happening. */
|
||||
if (VG_(clo_verbosity) > 0 && moans > 0) {
|
||||
moans--;
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"Warning: client switching stacks? "
|
||||
"SP change: %p --> %p", old_SP, new_SP);
|
||||
VG_(message)(Vg_UserMsg,
|
||||
" to suppress, use: --max-stackframe=%d or greater",
|
||||
(delta < 0 ? -delta : delta));
|
||||
if (moans == 0)
|
||||
VG_(message)(Vg_UserMsg,
|
||||
" further instances of this message "
|
||||
"will not be shown.");
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
VG_TRACK( new_mem_stack, new_SP, -delta );
|
||||
|
||||
} else if (delta > 0) {
|
||||
VG_TRACK( die_mem_stack, old_SP, delta );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Test if a piece of memory is addressable with at least the "prot"
|
||||
protection permissions by examining the underlying segments.
|
||||
@ -1544,5 +1279,5 @@ Bool VG_(setup_pointercheck)(Addr client_base, Addr client_end)
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end aspacemgr.c ---*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
#include "pub_core_redir.h"
|
||||
#include "pub_core_scheduler.h"
|
||||
#include "pub_core_signals.h"
|
||||
#include "pub_core_stacks.h" // Needed for VG_(register_stack)
|
||||
#include "pub_core_syswrap.h"
|
||||
#include "pub_core_tooliface.h"
|
||||
#include "pub_core_trampoline.h"
|
||||
@ -2715,7 +2716,7 @@ int main(int argc, char **argv, char **envp)
|
||||
//--------------------------------------------------------------
|
||||
// register client stack
|
||||
//--------------------------------------------------------------
|
||||
VG_(clstk_id) = VG_(handle_stack_register)(VG_(clstk_base), VG_(clstk_end));
|
||||
VG_(clstk_id) = VG_(register_stack)(VG_(clstk_base), VG_(clstk_end));
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Run!
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
#include "pub_core_replacemalloc.h"
|
||||
#include "pub_core_scheduler.h"
|
||||
#include "pub_core_signals.h"
|
||||
#include "pub_core_stacks.h"
|
||||
#include "pub_core_stacktrace.h" // For VG_(get_and_pp_StackTrace)()
|
||||
#include "pub_core_syscall.h"
|
||||
#include "pub_core_syswrap.h"
|
||||
@ -948,17 +949,17 @@ void do_client_request ( ThreadId tid )
|
||||
break; }
|
||||
|
||||
case VG_USERREQ__STACK_REGISTER: {
|
||||
UWord sid = VG_(handle_stack_register)((Addr)arg[1], (Addr)arg[2]);
|
||||
UWord sid = VG_(register_stack)((Addr)arg[1], (Addr)arg[2]);
|
||||
SET_CLREQ_RETVAL( tid, sid );
|
||||
break; }
|
||||
|
||||
case VG_USERREQ__STACK_DEREGISTER: {
|
||||
VG_(handle_stack_deregister)(arg[1]);
|
||||
VG_(deregister_stack)(arg[1]);
|
||||
SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
|
||||
break; }
|
||||
|
||||
case VG_USERREQ__STACK_CHANGE: {
|
||||
VG_(handle_stack_change)(arg[1], (Addr)arg[2], (Addr)arg[3]);
|
||||
VG_(change_stack)(arg[1], (Addr)arg[2], (Addr)arg[3]);
|
||||
SET_CLREQ_RETVAL( tid, 0 ); /* return value is meaningless */
|
||||
break; }
|
||||
|
||||
|
||||
@ -97,6 +97,7 @@
|
||||
#include "pub_core_scheduler.h"
|
||||
#include "pub_core_signals.h"
|
||||
#include "pub_core_sigframe.h" // For VG_(sigframe_create)()
|
||||
#include "pub_core_stacks.h" // For VG_(change_stack)()
|
||||
#include "pub_core_stacktrace.h" // For VG_(get_and_pp_StackTrace)()
|
||||
#include "pub_core_syscall.h"
|
||||
#include "pub_core_syswrap.h"
|
||||
@ -1737,7 +1738,7 @@ Bool VG_(extend_stack)(Addr addr, UInt maxsize)
|
||||
|
||||
/* When we change the main stack, we have to let the stack handling
|
||||
code know about it. */
|
||||
VG_(handle_stack_change)(VG_(clstk_id), base, VG_(clstk_end));
|
||||
VG_(change_stack)(VG_(clstk_id), base, VG_(clstk_end));
|
||||
|
||||
if (0)
|
||||
VG_(printf)("extended stack: %p %d\n",
|
||||
|
||||
283
coregrind/m_stacks.c
Normal file
283
coregrind/m_stacks.c
Normal file
@ -0,0 +1,283 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Stack management. m_stacks.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2000-2005 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
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.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
#include "pub_core_basics.h"
|
||||
#include "pub_core_libcprint.h"
|
||||
#include "pub_core_mallocfree.h"
|
||||
#include "pub_core_options.h"
|
||||
#include "pub_core_stacks.h"
|
||||
#include "pub_core_tooliface.h"
|
||||
|
||||
/*
|
||||
The stack
|
||||
~~~~~~~~~
|
||||
The stack's segment seems to be dynamically extended downwards by
|
||||
the kernel as the stack pointer moves down. Initially, a 1-page
|
||||
(4k) stack is allocated. When SP moves below that for the first
|
||||
time, presumably a page fault occurs. The kernel detects that the
|
||||
faulting address is in the range from SP - VG_STACK_REDZONE_SZB
|
||||
upwards to the current valid stack. It then extends the stack
|
||||
segment downwards for enough to cover the faulting address, and
|
||||
resumes the process (invisibly). The process is unaware of any of
|
||||
this.
|
||||
|
||||
That means that Valgrind can't spot when the stack segment is being
|
||||
extended. Fortunately, we want to precisely and continuously
|
||||
update stack permissions around SP, so we need to spot all writes
|
||||
to SP anyway.
|
||||
|
||||
The deal is: when SP is assigned a lower value, the stack is being
|
||||
extended. Create suitably-permissioned pages to fill in any holes
|
||||
between the old stack ptr and this one, if necessary. Then mark
|
||||
all bytes in the area just "uncovered" by this SP change as
|
||||
write-only.
|
||||
|
||||
When SP goes back up, mark the area receded over as unreadable and
|
||||
unwritable.
|
||||
|
||||
Just to record the SP boundary conditions somewhere convenient:
|
||||
SP - VG_STACK_REDZONE_SZB always points to the lowest live byte in
|
||||
the stack. All addresses below SP - VG_STACK_REDZONE_SZB are not
|
||||
live; those at and above it are.
|
||||
|
||||
We do not concern ourselves here with the VG_STACK_REDZONE_SZB
|
||||
bias; that is handled by new_mem_stack/die_mem_stack.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This structure holds information about the start and end addresses of
|
||||
* registered stacks. There's always at least one stack registered:
|
||||
* the main process stack. It will be the first stack registered and
|
||||
* so will have a stack id of 0. The user does not need to register
|
||||
* this stack: Valgrind does it automatically right before it starts
|
||||
* running the client. No other stacks are automatically registered by
|
||||
* Valgrind, however.
|
||||
*/
|
||||
typedef struct _Stack {
|
||||
UWord id;
|
||||
Addr start;
|
||||
Addr end;
|
||||
struct _Stack *next;
|
||||
} Stack;
|
||||
|
||||
static Stack *stacks;
|
||||
static UWord next_id; /* Next id we hand out to a newly registered stack */
|
||||
|
||||
/*
|
||||
* These are the id, start and end values of the current stack. If the
|
||||
* stack pointer falls outside the range of the current stack, we search
|
||||
* the stacks list above for a matching stack.
|
||||
*/
|
||||
static Addr current_stack_start;
|
||||
static Addr current_stack_end;
|
||||
static UWord current_stack_id;
|
||||
|
||||
/* Search for a particular stack by id number. */
|
||||
static Bool find_stack_by_id(UWord id, Addr *start, Addr *end)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
while(i) {
|
||||
if(i->id == id) {
|
||||
*start = i->start;
|
||||
*end = i->end;
|
||||
return True;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Find what stack an address falls into. */
|
||||
static Bool find_stack_by_addr(Addr sp, Addr *start, Addr *end, UWord *id)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
while(i) {
|
||||
if(sp >= i->start && sp <= i->end) {
|
||||
*start = i->start;
|
||||
*end = i->end;
|
||||
*id = i->id;
|
||||
return True;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Change over to a new stack. */
|
||||
static Bool set_current_stack(UWord id)
|
||||
{
|
||||
Addr start, end;
|
||||
if (find_stack_by_id(id, &start, &end)) {
|
||||
current_stack_id = id;
|
||||
current_stack_start = start;
|
||||
current_stack_end = end;
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a new stack from start - end. This is invoked from the
|
||||
* VALGRIND_STACK_REGISTER client request, and is also called just before
|
||||
* we start the client running, to register the main process stack.
|
||||
*/
|
||||
UWord VG_(register_stack)(Addr start, Addr end)
|
||||
{
|
||||
Stack *i;
|
||||
if (start > end) {
|
||||
Addr t = end;
|
||||
end = start;
|
||||
start = t;
|
||||
}
|
||||
|
||||
i = (Stack *)VG_(arena_malloc)(VG_AR_CORE, sizeof(Stack));
|
||||
i->start = start;
|
||||
i->end = end;
|
||||
i->id = next_id++;
|
||||
i->next = stacks;
|
||||
stacks = i;
|
||||
|
||||
if(i->id == 0) {
|
||||
set_current_stack(i->id);
|
||||
}
|
||||
|
||||
return i->id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deregister a stack. This is invoked from the VALGRIND_STACK_DEREGISTER
|
||||
* client request.
|
||||
*/
|
||||
void VG_(deregister_stack)(UWord id)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
Stack *prev = NULL;
|
||||
|
||||
if(current_stack_id == id) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(i) {
|
||||
if (i->id == id) {
|
||||
if(prev == NULL) {
|
||||
stacks = i->next;
|
||||
} else {
|
||||
prev->next = i->next;
|
||||
}
|
||||
VG_(arena_free)(VG_AR_CORE, i);
|
||||
return;
|
||||
}
|
||||
prev = i;
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change a stack. This is invoked from the VALGRIND_STACK_CHANGE client
|
||||
* request and from the stack growth stuff the signals module when
|
||||
* extending the main process stack.
|
||||
*/
|
||||
void VG_(change_stack)(UWord id, Addr start, Addr end)
|
||||
{
|
||||
Stack *i = stacks;
|
||||
|
||||
if (id == current_stack_id) {
|
||||
current_stack_start = start;
|
||||
current_stack_end = end;
|
||||
}
|
||||
|
||||
while(i) {
|
||||
if (i->id == id) {
|
||||
i->start = start;
|
||||
i->end = end;
|
||||
return;
|
||||
}
|
||||
i = i->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function gets called if new_mem_stack and/or die_mem_stack are
|
||||
tracked by the tool, and one of the specialised cases
|
||||
(eg. new_mem_stack_4) isn't used in preference.
|
||||
*/
|
||||
VG_REGPARM(2)
|
||||
void VG_(unknown_SP_update)( Addr old_SP, Addr new_SP )
|
||||
{
|
||||
static Int moans = 3;
|
||||
Word delta = (Word)new_SP - (Word)old_SP;
|
||||
|
||||
/* Check if the stack pointer is still in the same stack as before. */
|
||||
if (new_SP < current_stack_start || new_SP > current_stack_end) {
|
||||
Addr start, end;
|
||||
UWord new_id;
|
||||
Bool found = find_stack_by_addr(new_SP, &start, &end, &new_id);
|
||||
if (found && new_id != current_stack_id) {
|
||||
/* The stack pointer is now in another stack. Update the current
|
||||
stack information and return without doing anything else. */
|
||||
set_current_stack(new_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (delta < -VG_(clo_max_stackframe) || VG_(clo_max_stackframe) < delta) {
|
||||
/* SP has changed by more than some threshold amount (by
|
||||
default, 2MB). We take this to mean that the application is
|
||||
switching to a new stack, for whatever reason.
|
||||
|
||||
JRS 20021001: following discussions with John Regehr, if a stack
|
||||
switch happens, it seems best not to mess at all with memory
|
||||
permissions. Seems to work well with Netscape 4.X. Really the
|
||||
only remaining difficulty is knowing exactly when a stack switch is
|
||||
happening. */
|
||||
if (VG_(clo_verbosity) > 0 && moans > 0) {
|
||||
moans--;
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"Warning: client switching stacks? "
|
||||
"SP change: %p --> %p", old_SP, new_SP);
|
||||
VG_(message)(Vg_UserMsg,
|
||||
" to suppress, use: --max-stackframe=%d or greater",
|
||||
(delta < 0 ? -delta : delta));
|
||||
if (moans == 0)
|
||||
VG_(message)(Vg_UserMsg,
|
||||
" further instances of this message "
|
||||
"will not be shown.");
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
VG_TRACK( new_mem_stack, new_SP, -delta );
|
||||
|
||||
} else if (delta > 0) {
|
||||
VG_TRACK( die_mem_stack, old_SP, delta );
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
#include "pub_core_profile.h"
|
||||
#include "pub_core_redir.h" // For VG_(code_redirect)()
|
||||
#include "pub_core_signals.h" // For VG_(synth_fault_{perms,mapping})()
|
||||
#include "pub_core_stacks.h" // For VG_(unknown_SP_update)()
|
||||
#include "pub_core_tooliface.h" // For VG_(tdict)
|
||||
#include "pub_core_translate.h"
|
||||
#include "pub_core_transtab.h"
|
||||
|
||||
@ -132,13 +132,6 @@ extern Segment *VG_(split_segment)(Addr a);
|
||||
extern void VG_(pad_address_space) (Addr start);
|
||||
extern void VG_(unpad_address_space)(Addr start);
|
||||
|
||||
extern UWord VG_(handle_stack_register)(Addr start, Addr end);
|
||||
extern void VG_(handle_stack_deregister)(UWord id);
|
||||
extern void VG_(handle_stack_change)(UWord id, Addr start, Addr end);
|
||||
|
||||
extern VG_REGPARM(2)
|
||||
void VG_(unknown_SP_update) ( Addr old_SP, Addr new_SP );
|
||||
|
||||
///* Search /proc/self/maps for changes which aren't reflected in the
|
||||
// segment list */
|
||||
//extern void VG_(sync_segments)(UInt flags);
|
||||
|
||||
51
coregrind/pub_core_stacks.h
Normal file
51
coregrind/pub_core_stacks.h
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Stack management. m_stacks.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Valgrind, a dynamic binary instrumentation
|
||||
framework.
|
||||
|
||||
Copyright (C) 2000-2005 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
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.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
#ifndef __PUB_CORE_STACKS_H
|
||||
#define __PUB_CORE_STACKS_H
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// PURPOSE: This module deals with the registration of stacks for the
|
||||
// purposes of detecting stack switches.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
extern UWord VG_(register_stack) ( Addr start, Addr end );
|
||||
extern void VG_(deregister_stack) ( UWord id );
|
||||
extern void VG_(change_stack) ( UWord id, Addr start, Addr end );
|
||||
|
||||
extern VG_REGPARM(2)
|
||||
void VG_(unknown_SP_update) ( Addr old_SP, Addr new_SP );
|
||||
|
||||
#endif // __PUB_CORE_STACKS_H
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user