return __libc_send(s, msg, len, flags);
}
+extern
+int __libc_recv(int s, void *buf, size_t len, int flags);
+int recv(int s, void *buf, size_t len, int flags)
+{
+ return __libc_recv(s, buf, len, flags);
+}
+
/*--------------------------------------------------*/
ShadowChunk* sc;
UInt ml_no;
Bool ok;
+ ThreadId tid;
/* Perhaps it's a user-def'd block ? */
ok = VG_(client_perm_maybe_describe)( a, ai );
if (ok)
return;
- /* Perhaps it's on the stack? */
- if (VG_(is_plausible_stack_addr)(a)
- && a >= (Addr)VG_(baseBlock)[VGOFF_(m_esp)]) {
- ai->akind = Stack;
+ /* Perhaps it's on a thread's stack? */
+ tid = VG_(identify_stack_addr)(a);
+ if (tid != VG_INVALID_THREADID) {
+ ai->akind = Stack;
+ ai->stack_tid = tid;
return;
}
/* Search for a freed block which might bracket it. */
Char* syscall_param;
/* Param, User */
Bool isWriteableLack;
+ /* ALL */
+ ThreadId tid;
}
ErrContext;
ai->blksize = 0;
ai->rwoffset = 0;
ai->lastchange = NULL;
+ ai->stack_tid = VG_INVALID_THREADID;
}
static void clear_ErrContext ( ErrContext* ec )
clear_AddrInfo ( &ec->addrinfo );
ec->syscall_param = NULL;
ec->isWriteableLack = False;
+ ec->tid = VG_INVALID_THREADID;
}
{
switch (ai->akind) {
case Stack:
- VG_(message)(Vg_UserMsg, " Address 0x%x is on the stack", a);
+ VG_(message)(Vg_UserMsg,
+ " Address 0x%x is on thread %d's stack",
+ ai->stack_tid, a);
break;
case Unknown:
VG_(message)(Vg_UserMsg,
{
if (printCount)
VG_(message)(Vg_UserMsg, "Observed %d times:", ec->count );
+ if (ec->tid > 0)
+ VG_(message)(Vg_UserMsg, "Thread %d:", ec->tid );
switch (ec->ekind) {
case ValueErr:
if (ec->size == 0) {
static Bool slowdown_message = False;
static Int vg_n_errs_shown = 0;
+ vg_assert(ec->tid >= 0 && ec->tid < VG_N_THREADS);
+
/* After M_VG_COLLECT_NO_ERRORS_AFTER different errors have been
found, just refuse to collect any more. */
if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER) {
VG_(baseBlock)[VGOFF_(m_ebp)] );
ec.ekind = ValueErr;
ec.size = size;
+ ec.tid = VG_(get_current_tid)();
VG_(maybe_add_context) ( &ec );
}
ec.axskind = isWrite ? WriteAxs : ReadAxs;
ec.size = size;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_jump_error) ( Addr a )
+void VG_(record_free_error) ( Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.count = 1;
ec.next = NULL;
- ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
- VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = AddrErr;
- ec.axskind = ExecAxs;
+ ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
+ VG_(baseBlock)[VGOFF_(m_ebp)] );
+ ec.ekind = FreeErr;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_free_error) ( Addr a )
+void VG_(record_freemismatch_error) ( Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.next = NULL;
ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = FreeErr;
+ ec.ekind = FreeMismatchErr;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_freemismatch_error) ( Addr a )
+
+/* These three are called not from generated code but in response to
+ requests passed back to the scheduler. So we pick up %EIP/%EBP
+ values from the stored thread state, not from VG_(baseBlock). */
+
+void VG_(record_jump_error) ( ThreadState* tst, Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.count = 1;
ec.next = NULL;
- ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
- VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = FreeMismatchErr;
+ ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
+ ec.ekind = AddrErr;
+ ec.axskind = ExecAxs;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-/* These two are called not from generated code but in response to
- requests passed back to the scheduler. So we pick up %EIP/%EBP
- values from the stored thread state, not from VG_(baseBlock). */
-
void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack,
Char* msg )
{
ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
ec.ekind = ParamErr;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
ec.syscall_param = msg;
ec.isWriteableLack = isWriteLack;
VG_(maybe_add_context) ( &ec );
}
-
void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
{
ErrContext ec;
ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
ec.ekind = UserErr;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
ec.isWriteableLack = isWriteLack;
VG_(maybe_add_context) ( &ec );
pp_ErrContext( p_min, False );
if ((i+1 == VG_(clo_dump_error))) {
- VG_(translate) ( p_min->where->eips[0], NULL, NULL, NULL );
+ VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
+ p_min->where->eips[0], NULL, NULL, NULL );
}
p_min->count = 1 << 30;
#define VG_N_WAITING_FDS 10
/* Maximum number of mutexes allowed. */
-#define VG_N_MUTEXES 10
+#define VG_N_MUTEXES 30
/* ---------------------------------------------------------------------
struct {
/* The thread identity is simply the index in vg_threads[].
ThreadId == 0 is the root thread and has the special property
- that we don't try and allocate or deallocate its stack. */
+ that we don't try and allocate or deallocate its stack. For
+ convenience of generating error message, we also put the
+ ThreadId in this tid field, but be aware that it should
+ ALWAYS just == the index in vg_threads[]. */
+ ThreadId tid;
/* Current scheduling status. */
ThreadStatus status;
*/
Addr stack_base;
+ /* Address of the highest legitimate word in this stack. This is
+ used for error messages only -- not critical for execution
+ correctness. Is is set for all stacks, specifically including
+ ThreadId == 0 (the main thread). */
+ Addr stack_highest_word;
+
/* Saved machine context. */
UInt m_eax;
UInt m_ebx;
/* Get the thread state block for the specified thread. */
extern ThreadState* VG_(get_thread_state)( ThreadId );
+/* And for the currently running one, if valid. */
+extern ThreadState* VG_(get_current_thread_state) ( void );
+
+/* Similarly ... */
+extern ThreadId VG_(get_current_tid) ( void );
+
+/* Which thread is this address in the stack of, if any? Used for
+ error message generation. */
+extern ThreadId VG_(identify_stack_addr)( Addr a );
-/* Create, and add to TT/TC, the translation of a client basic
- block. */
-extern void VG_(create_translation_for) ( Addr orig_addr );
/* Return codes from the scheduler. */
typedef
Exports of vg_translate.c
------------------------------------------------------------------ */
-extern void VG_(translate) ( Addr orig_addr,
+extern void VG_(translate) ( ThreadState* tst,
+ Addr orig_addr,
UInt* orig_size,
Addr* trans_addr,
UInt* trans_size );
extern void VG_(record_freemismatch_error) ( Addr a );
extern void VG_(record_address_error) ( Addr a, Int size,
Bool isWrite );
-extern void VG_(record_jump_error) ( Addr a );
+
+extern void VG_(record_jump_error) ( ThreadState* tst, Addr a );
extern void VG_(record_param_err) ( ThreadState* tst,
Addr a,
Int rwoffset;
/* Freed, Mallocd */
ExeContext* lastchange;
+ /* Stack */
+ ThreadId stack_tid;
}
AddrInfo;
/* Nasty kludgery to deal with applications which switch stacks,
like netscape. */
-#define VG_STACK_STARTS_AT 0xC0000000
#define VG_PLAUSIBLE_STACK_SIZE 8000000
-extern Bool VG_(is_plausible_stack_addr) ( Addr );
-
/* ---------------------------------------------------------------------
Exports of vg_syscall_mem.c
return __libc_send(s, msg, len, flags);
}
+extern
+int __libc_recv(int s, void *buf, size_t len, int flags);
+int recv(int s, void *buf, size_t len, int flags)
+{
+ return __libc_recv(s, buf, len, flags);
+}
+
/*--------------------------------------------------*/
addresses below %esp are not live; those at and above it are.
*/
-/* Does this address look like something in the program's main
- stack ? */
-Bool VG_(is_plausible_stack_addr) ( Addr aa )
+/* Does this address look like something in or vaguely near the
+ current thread's stack? */
+static
+Bool is_plausible_stack_addr ( ThreadState* tst, Addr aa )
{
UInt a = (UInt)aa;
PROF_EVENT(100);
- if (a < VG_STACK_STARTS_AT &&
- a > VG_STACK_STARTS_AT - VG_PLAUSIBLE_STACK_SIZE)
+ if (a <= tst->stack_highest_word &&
+ a > tst->stack_highest_word - VG_PLAUSIBLE_STACK_SIZE)
return True;
else
return False;
- 0 * VKI_BYTES_PER_PAGE;
Addr valid_up_to = get_page_base(new_esp) + VKI_BYTES_PER_PAGE
+ 0 * VKI_BYTES_PER_PAGE;
+ ThreadState* tst = VG_(get_current_thread_state)();
PROF_EVENT(114);
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_UserMsg, "Warning: client switching stacks? "
/* VG_(printf)("na %p, %%esp %p, wr %p\n",
invalid_down_to, new_esp, valid_up_to ); */
VGM_(make_noaccess) ( invalid_down_to, new_esp - invalid_down_to );
- if (!VG_(is_plausible_stack_addr)(new_esp)) {
+ if (!is_plausible_stack_addr(tst, new_esp)) {
VGM_(make_readable) ( new_esp, valid_up_to - new_esp );
}
}
/* Private globals. A statically allocated array of threads. */
static ThreadState vg_threads[VG_N_THREADS];
+/* The tid of the thread currently in VG_(baseBlock). */
+static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
+
/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
jmp_buf VG_(scheduler_jmpbuf);
Helper functions for the scheduler.
------------------------------------------------------------------ */
+/* For constructing error messages only: try and identify a thread
+ whose stack this address currently falls within, or return
+ VG_INVALID_THREADID if it doesn't. A small complication is dealing
+ with any currently VG_(baseBlock)-resident thread.
+*/
+ThreadId VG_(identify_stack_addr)( Addr a )
+{
+ ThreadId tid, tid_to_skip;
+
+ tid_to_skip = VG_INVALID_THREADID;
+
+ /* First check to see if there's a currently-loaded thread in
+ VG_(baseBlock). */
+ if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
+ tid = vg_tid_currently_in_baseBlock;
+ if (VG_(baseBlock)[VGOFF_(m_esp)] <= a
+ && a <= vg_threads[tid].stack_highest_word)
+ return tid;
+ else
+ tid_to_skip = tid;
+ }
+
+ for (tid = 0; tid < VG_N_THREADS; tid++) {
+ if (vg_threads[tid].status == VgTs_Empty) continue;
+ if (tid == tid_to_skip) continue;
+ if (vg_threads[tid].m_esp <= a
+ && a <= vg_threads[tid].stack_highest_word)
+ return tid;
+ }
+ return VG_INVALID_THREADID;
+}
+
+
/* Print the scheduler status. */
void VG_(pp_sched_status) ( void )
{
orig_addr, and add it to the translation cache & translation table.
This probably doesn't really belong here, but, hey ...
*/
-void VG_(create_translation_for) ( Addr orig_addr )
+static
+void create_translation_for ( ThreadId tid, Addr orig_addr )
{
Addr trans_addr;
TTEntry tte;
Int orig_size, trans_size;
/* Ensure there is space to hold a translation. */
VG_(maybe_do_lru_pass)();
- VG_(translate)( orig_addr, &orig_size, &trans_addr, &trans_size );
+ VG_(translate)( &vg_threads[tid],
+ orig_addr, &orig_size, &trans_addr, &trans_size );
/* Copy data at trans_addr into the translation cache.
Returned pointer is to the code, not to the 4-byte
header. */
}
+ThreadState* VG_(get_current_thread_state) ( void )
+{
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+ return VG_(get_thread_state) ( VG_INVALID_THREADID );
+}
+
+
+ThreadId VG_(get_current_tid) ( void )
+{
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+ return vg_tid_currently_in_baseBlock;
+}
+
+
/* Find an unused VgMutex record. */
static
MutexId vg_alloc_VgMutex ( void )
void VG_(load_thread_state) ( ThreadId tid )
{
Int i;
+ vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
+
VG_(baseBlock)[VGOFF_(m_eax)] = vg_threads[tid].m_eax;
VG_(baseBlock)[VGOFF_(m_ebx)] = vg_threads[tid].m_ebx;
VG_(baseBlock)[VGOFF_(m_ecx)] = vg_threads[tid].m_ecx;
VG_(baseBlock)[VGOFF_(sh_ebp)] = vg_threads[tid].sh_ebp;
VG_(baseBlock)[VGOFF_(sh_esp)] = vg_threads[tid].sh_esp;
VG_(baseBlock)[VGOFF_(sh_eflags)] = vg_threads[tid].sh_eflags;
+
+ vg_tid_currently_in_baseBlock = tid;
}
Int i;
const UInt junk = 0xDEADBEEF;
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+
vg_threads[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
vg_threads[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
vg_threads[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
+
+ vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
}
for (i = 0; i < VG_N_THREADS; i++) {
vg_threads[i].stack_size = 0;
vg_threads[i].stack_base = (Addr)NULL;
+ vg_threads[i].tid = i;
}
for (i = 0; i < VG_N_WAITING_FDS; i++)
vg_threads[tid_main].status = VgTs_Runnable;
vg_threads[tid_main].joiner = VG_INVALID_THREADID;
vg_threads[tid_main].retval = NULL; /* not important */
+ vg_threads[tid_main].stack_highest_word
+ = vg_threads[tid_main].m_esp /* -4 ??? */;
/* Copy VG_(baseBlock) state to tid_main's slot. */
+ vg_tid_currently_in_baseBlock = tid_main;
VG_(save_thread_state) ( tid_main );
+
+ /* So now ... */
+ vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
}
/* ... and remember what we asked for. */
dispatch_ctr_SAVED = VG_(dispatch_ctr);
+ /* paranoia ... */
+ vg_assert(vg_threads[tid].tid == tid);
+
/* Actually run thread tid. */
while (True) {
= VG_(search_transtab) ( vg_threads[tid].m_eip );
if (trans_addr == (Addr)0) {
/* Not found; we need to request a translation. */
- VG_(create_translation_for)( vg_threads[tid].m_eip );
+ create_translation_for( tid, vg_threads[tid].m_eip );
trans_addr = VG_(search_transtab) ( vg_threads[tid].m_eip );
if (trans_addr == (Addr)0)
VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
throwing away the result. */
VG_(printf)(
"======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
- VG_(translate)( vg_threads[tid].m_eip, NULL, NULL, NULL );
+ VG_(translate)( &vg_threads[tid], vg_threads[tid].m_eip, NULL, NULL, NULL );
VG_(printf)("\n");
VG_(printf)(
"======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
vg_assert(vg_threads[parent_tid].status != VgTs_Empty);
- tid = vg_alloc_ThreadState();
+ tid = vg_alloc_ThreadState();
/* If we've created the main thread's tid, we're in deep trouble :) */
vg_assert(tid != 0);
new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb );
vg_threads[tid].stack_base = new_stack;
vg_threads[tid].stack_size = new_stk_szb;
- vg_threads[tid].m_esp
+ vg_threads[tid].stack_highest_word
= new_stack + new_stk_szb
- - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
+ - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
}
+
+ vg_threads[tid].m_esp
+ = vg_threads[tid].stack_base
+ + vg_threads[tid].stack_size
+ - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
+
if (VG_(clo_instrument))
VGM_(make_noaccess)( vg_threads[tid].m_esp,
VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
throw away the translation once it is made, and (b) produce a load
of debugging output.
*/
-void VG_(translate) ( Addr orig_addr,
+void VG_(translate) ( ThreadState* tst,
+ /* Identity of thread needing this block */
+ Addr orig_addr,
UInt* orig_size,
Addr* trans_addr,
UInt* trans_size )
Addr bad_addr;
Bool ok = VGM_(check_readable) ( orig_addr, 1, &bad_addr );
if (!ok) {
- VG_(record_jump_error)(bad_addr);
+ VG_(record_jump_error)(tst, bad_addr);
}
}
ShadowChunk* sc;
UInt ml_no;
Bool ok;
+ ThreadId tid;
/* Perhaps it's a user-def'd block ? */
ok = VG_(client_perm_maybe_describe)( a, ai );
if (ok)
return;
- /* Perhaps it's on the stack? */
- if (VG_(is_plausible_stack_addr)(a)
- && a >= (Addr)VG_(baseBlock)[VGOFF_(m_esp)]) {
- ai->akind = Stack;
+ /* Perhaps it's on a thread's stack? */
+ tid = VG_(identify_stack_addr)(a);
+ if (tid != VG_INVALID_THREADID) {
+ ai->akind = Stack;
+ ai->stack_tid = tid;
return;
}
/* Search for a freed block which might bracket it. */
Char* syscall_param;
/* Param, User */
Bool isWriteableLack;
+ /* ALL */
+ ThreadId tid;
}
ErrContext;
ai->blksize = 0;
ai->rwoffset = 0;
ai->lastchange = NULL;
+ ai->stack_tid = VG_INVALID_THREADID;
}
static void clear_ErrContext ( ErrContext* ec )
clear_AddrInfo ( &ec->addrinfo );
ec->syscall_param = NULL;
ec->isWriteableLack = False;
+ ec->tid = VG_INVALID_THREADID;
}
{
switch (ai->akind) {
case Stack:
- VG_(message)(Vg_UserMsg, " Address 0x%x is on the stack", a);
+ VG_(message)(Vg_UserMsg,
+ " Address 0x%x is on thread %d's stack",
+ ai->stack_tid, a);
break;
case Unknown:
VG_(message)(Vg_UserMsg,
{
if (printCount)
VG_(message)(Vg_UserMsg, "Observed %d times:", ec->count );
+ if (ec->tid > 0)
+ VG_(message)(Vg_UserMsg, "Thread %d:", ec->tid );
switch (ec->ekind) {
case ValueErr:
if (ec->size == 0) {
static Bool slowdown_message = False;
static Int vg_n_errs_shown = 0;
+ vg_assert(ec->tid >= 0 && ec->tid < VG_N_THREADS);
+
/* After M_VG_COLLECT_NO_ERRORS_AFTER different errors have been
found, just refuse to collect any more. */
if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER) {
VG_(baseBlock)[VGOFF_(m_ebp)] );
ec.ekind = ValueErr;
ec.size = size;
+ ec.tid = VG_(get_current_tid)();
VG_(maybe_add_context) ( &ec );
}
ec.axskind = isWrite ? WriteAxs : ReadAxs;
ec.size = size;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_jump_error) ( Addr a )
+void VG_(record_free_error) ( Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.count = 1;
ec.next = NULL;
- ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
- VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = AddrErr;
- ec.axskind = ExecAxs;
+ ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
+ VG_(baseBlock)[VGOFF_(m_ebp)] );
+ ec.ekind = FreeErr;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_free_error) ( Addr a )
+void VG_(record_freemismatch_error) ( Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.next = NULL;
ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = FreeErr;
+ ec.ekind = FreeMismatchErr;
ec.addr = a;
+ ec.tid = VG_(get_current_tid)();
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-void VG_(record_freemismatch_error) ( Addr a )
+
+/* These three are called not from generated code but in response to
+ requests passed back to the scheduler. So we pick up %EIP/%EBP
+ values from the stored thread state, not from VG_(baseBlock). */
+
+void VG_(record_jump_error) ( ThreadState* tst, Addr a )
{
ErrContext ec;
clear_ErrContext( &ec );
ec.count = 1;
ec.next = NULL;
- ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
- VG_(baseBlock)[VGOFF_(m_ebp)] );
- ec.ekind = FreeMismatchErr;
+ ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
+ ec.ekind = AddrErr;
+ ec.axskind = ExecAxs;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
VG_(maybe_add_context) ( &ec );
}
-/* These two are called not from generated code but in response to
- requests passed back to the scheduler. So we pick up %EIP/%EBP
- values from the stored thread state, not from VG_(baseBlock). */
-
void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack,
Char* msg )
{
ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
ec.ekind = ParamErr;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
ec.syscall_param = msg;
ec.isWriteableLack = isWriteLack;
VG_(maybe_add_context) ( &ec );
}
-
void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
{
ErrContext ec;
ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
ec.ekind = UserErr;
ec.addr = a;
+ ec.tid = tst->tid;
VG_(describe_addr) ( a, &ec.addrinfo );
ec.isWriteableLack = isWriteLack;
VG_(maybe_add_context) ( &ec );
pp_ErrContext( p_min, False );
if ((i+1 == VG_(clo_dump_error))) {
- VG_(translate) ( p_min->where->eips[0], NULL, NULL, NULL );
+ VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
+ p_min->where->eips[0], NULL, NULL, NULL );
}
p_min->count = 1 << 30;
#define VG_N_WAITING_FDS 10
/* Maximum number of mutexes allowed. */
-#define VG_N_MUTEXES 10
+#define VG_N_MUTEXES 30
/* ---------------------------------------------------------------------
struct {
/* The thread identity is simply the index in vg_threads[].
ThreadId == 0 is the root thread and has the special property
- that we don't try and allocate or deallocate its stack. */
+ that we don't try and allocate or deallocate its stack. For
+ convenience of generating error message, we also put the
+ ThreadId in this tid field, but be aware that it should
+ ALWAYS just == the index in vg_threads[]. */
+ ThreadId tid;
/* Current scheduling status. */
ThreadStatus status;
*/
Addr stack_base;
+ /* Address of the highest legitimate word in this stack. This is
+ used for error messages only -- not critical for execution
+ correctness. Is is set for all stacks, specifically including
+ ThreadId == 0 (the main thread). */
+ Addr stack_highest_word;
+
/* Saved machine context. */
UInt m_eax;
UInt m_ebx;
/* Get the thread state block for the specified thread. */
extern ThreadState* VG_(get_thread_state)( ThreadId );
+/* And for the currently running one, if valid. */
+extern ThreadState* VG_(get_current_thread_state) ( void );
+
+/* Similarly ... */
+extern ThreadId VG_(get_current_tid) ( void );
+
+/* Which thread is this address in the stack of, if any? Used for
+ error message generation. */
+extern ThreadId VG_(identify_stack_addr)( Addr a );
-/* Create, and add to TT/TC, the translation of a client basic
- block. */
-extern void VG_(create_translation_for) ( Addr orig_addr );
/* Return codes from the scheduler. */
typedef
Exports of vg_translate.c
------------------------------------------------------------------ */
-extern void VG_(translate) ( Addr orig_addr,
+extern void VG_(translate) ( ThreadState* tst,
+ Addr orig_addr,
UInt* orig_size,
Addr* trans_addr,
UInt* trans_size );
extern void VG_(record_freemismatch_error) ( Addr a );
extern void VG_(record_address_error) ( Addr a, Int size,
Bool isWrite );
-extern void VG_(record_jump_error) ( Addr a );
+
+extern void VG_(record_jump_error) ( ThreadState* tst, Addr a );
extern void VG_(record_param_err) ( ThreadState* tst,
Addr a,
Int rwoffset;
/* Freed, Mallocd */
ExeContext* lastchange;
+ /* Stack */
+ ThreadId stack_tid;
}
AddrInfo;
/* Nasty kludgery to deal with applications which switch stacks,
like netscape. */
-#define VG_STACK_STARTS_AT 0xC0000000
#define VG_PLAUSIBLE_STACK_SIZE 8000000
-extern Bool VG_(is_plausible_stack_addr) ( Addr );
-
/* ---------------------------------------------------------------------
Exports of vg_syscall_mem.c
return __libc_send(s, msg, len, flags);
}
+extern
+int __libc_recv(int s, void *buf, size_t len, int flags);
+int recv(int s, void *buf, size_t len, int flags)
+{
+ return __libc_recv(s, buf, len, flags);
+}
+
/*--------------------------------------------------*/
addresses below %esp are not live; those at and above it are.
*/
-/* Does this address look like something in the program's main
- stack ? */
-Bool VG_(is_plausible_stack_addr) ( Addr aa )
+/* Does this address look like something in or vaguely near the
+ current thread's stack? */
+static
+Bool is_plausible_stack_addr ( ThreadState* tst, Addr aa )
{
UInt a = (UInt)aa;
PROF_EVENT(100);
- if (a < VG_STACK_STARTS_AT &&
- a > VG_STACK_STARTS_AT - VG_PLAUSIBLE_STACK_SIZE)
+ if (a <= tst->stack_highest_word &&
+ a > tst->stack_highest_word - VG_PLAUSIBLE_STACK_SIZE)
return True;
else
return False;
- 0 * VKI_BYTES_PER_PAGE;
Addr valid_up_to = get_page_base(new_esp) + VKI_BYTES_PER_PAGE
+ 0 * VKI_BYTES_PER_PAGE;
+ ThreadState* tst = VG_(get_current_thread_state)();
PROF_EVENT(114);
if (VG_(clo_verbosity) > 1)
VG_(message)(Vg_UserMsg, "Warning: client switching stacks? "
/* VG_(printf)("na %p, %%esp %p, wr %p\n",
invalid_down_to, new_esp, valid_up_to ); */
VGM_(make_noaccess) ( invalid_down_to, new_esp - invalid_down_to );
- if (!VG_(is_plausible_stack_addr)(new_esp)) {
+ if (!is_plausible_stack_addr(tst, new_esp)) {
VGM_(make_readable) ( new_esp, valid_up_to - new_esp );
}
}
/* Private globals. A statically allocated array of threads. */
static ThreadState vg_threads[VG_N_THREADS];
+/* The tid of the thread currently in VG_(baseBlock). */
+static Int vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
+
/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
jmp_buf VG_(scheduler_jmpbuf);
Helper functions for the scheduler.
------------------------------------------------------------------ */
+/* For constructing error messages only: try and identify a thread
+ whose stack this address currently falls within, or return
+ VG_INVALID_THREADID if it doesn't. A small complication is dealing
+ with any currently VG_(baseBlock)-resident thread.
+*/
+ThreadId VG_(identify_stack_addr)( Addr a )
+{
+ ThreadId tid, tid_to_skip;
+
+ tid_to_skip = VG_INVALID_THREADID;
+
+ /* First check to see if there's a currently-loaded thread in
+ VG_(baseBlock). */
+ if (vg_tid_currently_in_baseBlock != VG_INVALID_THREADID) {
+ tid = vg_tid_currently_in_baseBlock;
+ if (VG_(baseBlock)[VGOFF_(m_esp)] <= a
+ && a <= vg_threads[tid].stack_highest_word)
+ return tid;
+ else
+ tid_to_skip = tid;
+ }
+
+ for (tid = 0; tid < VG_N_THREADS; tid++) {
+ if (vg_threads[tid].status == VgTs_Empty) continue;
+ if (tid == tid_to_skip) continue;
+ if (vg_threads[tid].m_esp <= a
+ && a <= vg_threads[tid].stack_highest_word)
+ return tid;
+ }
+ return VG_INVALID_THREADID;
+}
+
+
/* Print the scheduler status. */
void VG_(pp_sched_status) ( void )
{
orig_addr, and add it to the translation cache & translation table.
This probably doesn't really belong here, but, hey ...
*/
-void VG_(create_translation_for) ( Addr orig_addr )
+static
+void create_translation_for ( ThreadId tid, Addr orig_addr )
{
Addr trans_addr;
TTEntry tte;
Int orig_size, trans_size;
/* Ensure there is space to hold a translation. */
VG_(maybe_do_lru_pass)();
- VG_(translate)( orig_addr, &orig_size, &trans_addr, &trans_size );
+ VG_(translate)( &vg_threads[tid],
+ orig_addr, &orig_size, &trans_addr, &trans_size );
/* Copy data at trans_addr into the translation cache.
Returned pointer is to the code, not to the 4-byte
header. */
}
+ThreadState* VG_(get_current_thread_state) ( void )
+{
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+ return VG_(get_thread_state) ( VG_INVALID_THREADID );
+}
+
+
+ThreadId VG_(get_current_tid) ( void )
+{
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+ return vg_tid_currently_in_baseBlock;
+}
+
+
/* Find an unused VgMutex record. */
static
MutexId vg_alloc_VgMutex ( void )
void VG_(load_thread_state) ( ThreadId tid )
{
Int i;
+ vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
+
VG_(baseBlock)[VGOFF_(m_eax)] = vg_threads[tid].m_eax;
VG_(baseBlock)[VGOFF_(m_ebx)] = vg_threads[tid].m_ebx;
VG_(baseBlock)[VGOFF_(m_ecx)] = vg_threads[tid].m_ecx;
VG_(baseBlock)[VGOFF_(sh_ebp)] = vg_threads[tid].sh_ebp;
VG_(baseBlock)[VGOFF_(sh_esp)] = vg_threads[tid].sh_esp;
VG_(baseBlock)[VGOFF_(sh_eflags)] = vg_threads[tid].sh_eflags;
+
+ vg_tid_currently_in_baseBlock = tid;
}
Int i;
const UInt junk = 0xDEADBEEF;
+ vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID);
+
vg_threads[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)];
vg_threads[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)];
vg_threads[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)];
for (i = 0; i < VG_SIZE_OF_FPUSTATE_W; i++)
VG_(baseBlock)[VGOFF_(m_fpustate) + i] = junk;
+
+ vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
}
for (i = 0; i < VG_N_THREADS; i++) {
vg_threads[i].stack_size = 0;
vg_threads[i].stack_base = (Addr)NULL;
+ vg_threads[i].tid = i;
}
for (i = 0; i < VG_N_WAITING_FDS; i++)
vg_threads[tid_main].status = VgTs_Runnable;
vg_threads[tid_main].joiner = VG_INVALID_THREADID;
vg_threads[tid_main].retval = NULL; /* not important */
+ vg_threads[tid_main].stack_highest_word
+ = vg_threads[tid_main].m_esp /* -4 ??? */;
/* Copy VG_(baseBlock) state to tid_main's slot. */
+ vg_tid_currently_in_baseBlock = tid_main;
VG_(save_thread_state) ( tid_main );
+
+ /* So now ... */
+ vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID);
}
/* ... and remember what we asked for. */
dispatch_ctr_SAVED = VG_(dispatch_ctr);
+ /* paranoia ... */
+ vg_assert(vg_threads[tid].tid == tid);
+
/* Actually run thread tid. */
while (True) {
= VG_(search_transtab) ( vg_threads[tid].m_eip );
if (trans_addr == (Addr)0) {
/* Not found; we need to request a translation. */
- VG_(create_translation_for)( vg_threads[tid].m_eip );
+ create_translation_for( tid, vg_threads[tid].m_eip );
trans_addr = VG_(search_transtab) ( vg_threads[tid].m_eip );
if (trans_addr == (Addr)0)
VG_(panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry");
throwing away the result. */
VG_(printf)(
"======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
- VG_(translate)( vg_threads[tid].m_eip, NULL, NULL, NULL );
+ VG_(translate)( &vg_threads[tid], vg_threads[tid].m_eip, NULL, NULL, NULL );
VG_(printf)("\n");
VG_(printf)(
"======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
vg_assert(vg_threads[parent_tid].status != VgTs_Empty);
- tid = vg_alloc_ThreadState();
+ tid = vg_alloc_ThreadState();
/* If we've created the main thread's tid, we're in deep trouble :) */
vg_assert(tid != 0);
new_stack = (Addr)VG_(get_memory_from_mmap)( new_stk_szb );
vg_threads[tid].stack_base = new_stack;
vg_threads[tid].stack_size = new_stk_szb;
- vg_threads[tid].m_esp
+ vg_threads[tid].stack_highest_word
= new_stack + new_stk_szb
- - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
+ - VG_AR_CLIENT_STACKBASE_REDZONE_SZB; /* -4 ??? */;
}
+
+ vg_threads[tid].m_esp
+ = vg_threads[tid].stack_base
+ + vg_threads[tid].stack_size
+ - VG_AR_CLIENT_STACKBASE_REDZONE_SZB;
+
if (VG_(clo_instrument))
VGM_(make_noaccess)( vg_threads[tid].m_esp,
VG_AR_CLIENT_STACKBASE_REDZONE_SZB );
throw away the translation once it is made, and (b) produce a load
of debugging output.
*/
-void VG_(translate) ( Addr orig_addr,
+void VG_(translate) ( ThreadState* tst,
+ /* Identity of thread needing this block */
+ Addr orig_addr,
UInt* orig_size,
Addr* trans_addr,
UInt* trans_size )
Addr bad_addr;
Bool ok = VGM_(check_readable) ( orig_addr, 1, &bad_addr );
if (!ok) {
- VG_(record_jump_error)(bad_addr);
+ VG_(record_jump_error)(tst, bad_addr);
}
}