Yay!  Opera (6.0TP2) now works.

Various enhancements:

* Make the error message system more thread-aware.

* Fix stupid bug in do_pthread_create causing incorrect initial
  %ESP values sometimes.

* Fix various other minor things needed to make opera work.

Performance of threaded apps is pretty terrible.  This needs
looking into.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@98 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c
index c632124..0ac2cb3 100644
--- a/coregrind/vg_errcontext.c
+++ b/coregrind/vg_errcontext.c
@@ -142,6 +142,8 @@
       Char* syscall_param;
       /* Param, User */
       Bool isWriteableLack;
+      /* ALL */
+      ThreadId tid;
    } 
    ErrContext;
 
@@ -174,6 +176,7 @@
    ai->blksize    = 0;
    ai->rwoffset   = 0;
    ai->lastchange = NULL;
+   ai->stack_tid  = VG_INVALID_THREADID;
 }
 
 static void clear_ErrContext ( ErrContext* ec )
@@ -189,6 +192,7 @@
    clear_AddrInfo ( &ec->addrinfo );
    ec->syscall_param   = NULL;
    ec->isWriteableLack = False;
+   ec->tid     = VG_INVALID_THREADID;
 }
 
 
@@ -264,7 +268,9 @@
 {
    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, 
@@ -309,6 +315,8 @@
 {
    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) {
@@ -441,6 +449,8 @@
    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) {
@@ -551,6 +561,7 @@
                                           VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind = ValueErr;
    ec.size  = size;
+   ec.tid   = VG_(get_current_tid)();
    VG_(maybe_add_context) ( &ec );
 }
 
@@ -573,21 +584,7 @@
    ec.axskind = isWrite ? WriteAxs : ReadAxs;
    ec.size    = size;
    ec.addr    = a;
-   VG_(describe_addr) ( a, &ec.addrinfo );
-   VG_(maybe_add_context) ( &ec );
-}
-
-void VG_(record_jump_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.addr    = a;
+   ec.tid     = VG_(get_current_tid)();
    VG_(describe_addr) ( a, &ec.addrinfo );
    VG_(maybe_add_context) ( &ec );
 }
@@ -602,6 +599,7 @@
                                            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 );
 }
@@ -616,14 +614,31 @@
                                            VG_(baseBlock)[VGOFF_(m_ebp)] );
    ec.ekind   = FreeMismatchErr;
    ec.addr    = a;
+   ec.tid     = VG_(get_current_tid)();
    VG_(describe_addr) ( a, &ec.addrinfo );
    VG_(maybe_add_context) ( &ec );
 }
 
-/* These two are called not from generated code but in response to
+
+/* 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)( 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 );
+}
+
 void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack, 
                              Char* msg )
 {
@@ -634,13 +649,13 @@
    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;
@@ -650,6 +665,7 @@
    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 );
@@ -710,7 +726,8 @@
       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;