A new kind of error: PThread errors.  Used to report detected misuse in
the pthread_* API.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@379 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c
index 6175339..d5e0abb 100644
--- a/coregrind/vg_errcontext.c
+++ b/coregrind/vg_errcontext.c
@@ -53,7 +53,9 @@
       /* Invalid read/write attempt at given size */
       Addr1, Addr2, Addr4, Addr8,
       /* Invalid or mismatching free */
-      FreeS
+      FreeS,
+      /* Pthreading error */
+      PThread
    } 
    SuppressionKind;
 
@@ -108,7 +110,9 @@
 typedef 
    enum { ValueErr, AddrErr, 
           ParamErr, UserErr, /* behaves like an anonymous ParamErr */
-          FreeErr, FreeMismatchErr }
+          FreeErr, FreeMismatchErr,
+          PThreadErr /* pthread API error */
+   }
    ErrKind;
 
 /* What kind of memory access is involved in the error? */
@@ -138,7 +142,7 @@
       Addr addr;
       /* Addr, Free, Param, User */
       AddrInfo addrinfo;
-      /* Param */
+      /* Param; hijacked for PThread as a description */
       Char* syscall_param;
       /* Param, User */
       Bool isWriteableLack;
@@ -255,6 +259,12 @@
       return False;
 
    switch (e1->ekind) {
+      case PThreadErr:
+         if (e1->syscall_param == e2->syscall_param) 
+            return True;
+         if (0 == VG_(strcmp)(e1->syscall_param, e2->syscall_param))
+            return True;
+         return False;
       case UserErr:
       case ParamErr:
          if (e1->isWriteableLack != e2->isWriteableLack) return False;
@@ -412,6 +422,10 @@
          VG_(pp_ExeContext)(ec->where);
          pp_AddrInfo(ec->addr, &ec->addrinfo);
          break;
+      case PThreadErr:
+         VG_(message)(Vg_UserMsg, "%s", ec->syscall_param );
+         VG_(pp_ExeContext)(ec->where);
+         break;
       default: 
          VG_(panic)("pp_ErrContext");
    }
@@ -747,6 +761,25 @@
    VG_(maybe_add_context) ( &ec );
 }
 
+void VG_(record_pthread_err) ( ThreadId tid, Char* msg )
+{
+   ErrContext ec;
+   if (vg_ignore_errors) return;
+   if (!VG_(clo_instrument)) return;
+   clear_ErrContext( &ec );
+   ec.count   = 1;
+   ec.next    = NULL;
+   ec.where   = VG_(get_ExeContext)( False, VG_(threads)[tid].m_eip, 
+                                            VG_(threads)[tid].m_ebp );
+   ec.ekind   = PThreadErr;
+   ec.tid     = tid;
+   ec.syscall_param = msg;
+   ec.m_eip   = VG_(threads)[tid].m_eip;
+   ec.m_esp   = VG_(threads)[tid].m_esp;
+   ec.m_ebp   = VG_(threads)[tid].m_ebp;
+   VG_(maybe_add_context) ( &ec );
+}
+
 
 /*------------------------------*/
 
@@ -963,6 +996,7 @@
       else if (STREQ(buf, "Addr4"))  supp->skind = Addr4;
       else if (STREQ(buf, "Addr8"))  supp->skind = Addr8;
       else if (STREQ(buf, "Free"))   supp->skind = FreeS;
+      else if (STREQ(buf, "PThread")) supp->skind = PThread;
       else goto syntax_error;
 
       if (supp->skind == Param) {
@@ -1100,7 +1134,7 @@
    /* See if the error context matches any suppression. */
    for (su = vg_suppressions; su != NULL; su = su->next) {
       switch (su->skind) {
-         case FreeS:
+         case FreeS:  case PThread:
          case Param:  case Value0: su_size = 0; break;
          case Value1: case Addr1:  su_size = 1; break;
          case Value2: case Addr2:  su_size = 2; break;
@@ -1122,7 +1156,11 @@
             if (ec->size  != su_size) continue;
             break;
          case FreeS:
-            if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
+            if (ec->ekind != FreeErr 
+                && ec->ekind != FreeMismatchErr) continue;
+            break;
+         case PThread:
+            if (ec->ekind != PThreadErr) continue;
             break;
       }