]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Intercept prctl(PR_SET_NAME, name) and store the thread name so it
authorFlorian Krohm <florian@eich-krohm.de>
Mon, 16 Sep 2013 17:08:50 +0000 (17:08 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Mon, 16 Sep 2013 17:08:50 +0000 (17:08 +0000)
can be used in error messages. That should be helpful when debugging
multithreaded applications.
Patch by Matthias Schwarzott <zzam@gentoo.org> with some minor
modifications. Fixes BZ 322254.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13553

13 files changed:
NEWS
coregrind/m_errormgr.c
coregrind/m_gdbserver/server.c
coregrind/m_scheduler/scheduler.c
coregrind/m_syswrap/syswrap-linux.c
coregrind/pub_core_threadstate.h
docs/internals/xml-output-protocol4.txt
memcheck/tests/Makefile.am
memcheck/tests/threadname.c [new file with mode: 0644]
memcheck/tests/threadname.stderr.exp [new file with mode: 0644]
memcheck/tests/threadname.vgtest [new file with mode: 0644]
memcheck/tests/threadname_xml.stderr.exp [new file with mode: 0644]
memcheck/tests/threadname_xml.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index d489a78e83546f584aa20404789963ecdbd56834..4d0fbd88a53779210c48a5fedf778e74b428797a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -464,6 +464,9 @@ FIXED r??
 321969  ppc32 and ppc64 don't support [lf]setxattr
         FIXED r13449
 
+322254  Show threadname together with tid if set by application
+        FIXED r13553
+
 322368  Assertion failure in wqthread_hijack under OS X 10.8
         FIXED 13523
 
index 1374cd421d23cd72bbf0afb59ebe3dbcf929b6dd..35b334f0db95a272f83f6aa781b046143abc3f7e 100644 (file)
@@ -591,6 +591,10 @@ static void pp_Error ( Error* err, Bool allow_db_attach, Bool xml )
       VG_(printf_xml)("<error>\n");
       VG_(printf_xml)("  <unique>0x%x</unique>\n", err->unique);
       VG_(printf_xml)("  <tid>%d</tid>\n", err->tid);
+      ThreadState* tst = VG_(get_ThreadState)(err->tid);
+      if (tst->thread_name) {
+         VG_(printf_xml)("  <threadname>%s</threadname>\n", tst->thread_name);
+      }
 
       /* actually print it */
       VG_TDICT_CALL( tool_pp_Error, err );
@@ -608,7 +612,12 @@ static void pp_Error ( Error* err, Bool allow_db_attach, Bool xml )
 
       if (VG_(tdict).tool_show_ThreadIDs_for_errors
           && err->tid > 0 && err->tid != last_tid_printed) {
-         VG_(umsg)("Thread %d:\n", err->tid );
+         ThreadState* tst = VG_(get_ThreadState)(err->tid);
+         if (tst->thread_name) {
+            VG_(umsg)("Thread %d %s:\n", err->tid, tst->thread_name );
+         } else {
+            VG_(umsg)("Thread %d:\n", err->tid );
+         }
          last_tid_printed = err->tid;
       }
    
index 46abb7cfa690f5fb9ea4c92e106dc1953ae0a777..9feb0f61a53a49f155c413b279e14661cb549468 100644 (file)
@@ -588,10 +588,18 @@ void handle_query (char *arg_own_buf, int *new_packet_len_p)
       ti = gdb_id_to_thread (gdb_id);
       if (ti != NULL) {
          tst = (ThreadState *) inferior_target_data (ti);
-         /* Additional info is the tid and the thread status. */
-         VG_(snprintf) (status, sizeof(status), "tid %d %s",
-                        tst->tid, 
-                        VG_(name_of_ThreadStatus)(tst->status));
+         /* Additional info is the tid, the thread status and the thread's
+            name, if any. */
+         if (tst->thread_name) {
+            VG_(snprintf) (status, sizeof(status), "tid %d %s %s",
+                           tst->tid, 
+                           VG_(name_of_ThreadStatus)(tst->status),
+                           tst->thread_name);
+         } else {
+            VG_(snprintf) (status, sizeof(status), "tid %d %s",
+                           tst->tid, 
+                           VG_(name_of_ThreadStatus)(tst->status));
+         }
          hexify (arg_own_buf, status, strlen(status));
          return;
       } else {
index b20ab919aeebcc0f4e6668160af5261421362d73..f0fb675239644fbb72ffbbb28a249f7a7ad1ea5d 100644 (file)
@@ -238,6 +238,7 @@ ThreadId VG_(alloc_ThreadState) ( void )
       if (VG_(threads)[i].status == VgTs_Empty) {
         VG_(threads)[i].status = VgTs_Init;
         VG_(threads)[i].exitreason = VgSrc_None;
+        VG_(threads)[i].thread_name = NULL;
          return i;
       }
    }
@@ -616,6 +617,7 @@ ThreadId VG_(scheduler_init_phase1) ( void )
       VG_(threads)[i].client_stack_szB          = 0;
       VG_(threads)[i].client_stack_highest_word = (Addr)NULL;
       VG_(threads)[i].err_disablement_level     = 0;
+      VG_(threads)[i].thread_name               = NULL;
    }
 
    tid_main = VG_(alloc_ThreadState)();
index 1db46e0ad86610187e13d76dcc663e2d4a19b551..e948bd555ebd32593360d8dcd14fa0589f69a4bf 100644 (file)
@@ -946,6 +946,18 @@ POST(sys_prctl)
    case VKI_PR_GET_ENDIAN:
       POST_MEM_WRITE(ARG2, sizeof(Int));
       break;
+   case VKI_PR_SET_NAME:
+      {
+         const HChar* new_name = (const HChar*) ARG2;
+         if (new_name) {    // Paranoia
+            ThreadState* tst = VG_(get_ThreadState)(tid);
+
+            /* Don't bother reusing the memory. This is a rare event. */
+            tst->thread_name =
+              VG_(arena_strdup)(VG_AR_CORE, "syswrap.prctl", new_name);
+         }
+      }
+      break;
    }
 }
 
index 54dce4a58889bcd4367e7eda957b78b7efc41766..cfe212113024bc1763c72f0435fb81c58e0e17ca 100644 (file)
@@ -357,6 +357,9 @@ typedef struct {
    /* Per-thread jmp_buf to resume scheduler after a signal */
    Bool               sched_jmpbuf_valid;
    VG_MINIMAL_JMP_BUF(sched_jmpbuf);
+
+   /* This thread's name. NULL, if no name. */
+   HChar *thread_name;
 }
 ThreadState;
 
index 861d8ca21b04c7f0e56b0c49c5c63212b6cd2405..a147eaa4cbb7f144148ac18606c8a43502854497 100644 (file)
@@ -408,6 +408,7 @@ following:
   <error>
      <unique>HEX64</unique>
      <tid>INT</tid>
+     <threadname>NAME</threadname>    if set
      <kind>KIND</kind>
 
      (either WHAT or XWHAT)
@@ -428,6 +429,10 @@ following:
   is arbitrary but may be used to determine which threads produced
   which errors (at least, the first instance of each error).
 
+* The <threadname> tag identifies the name of the thread if it was
+  set by the client application. If no name was set, the tag is
+  omitted.
+
 * The <kind> tag specifies one of a small number of fixed error types,
   so that GUIs may roughly categorise errors by type if they want.
   The tags themselves are tool-specific and are defined further
index 293813323e43f18ffb985c9ea5757c6a734f92bc..2951423dd867a41b63b914c72d709de8905b7c36 100644 (file)
@@ -260,7 +260,10 @@ EXTRA_DIST = \
        wrap8.vgtest wrap8.stdout.exp wrap8.stderr.exp \
        wrap8.stdout.exp2 wrap8.stderr.exp2 \
        writev1.stderr.exp writev1.vgtest \
-       xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc
+       xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \
+       threadname.vgtest threadname.stdout.exp threadname.stderr.exp \
+       threadname_xml.vgtest threadname_xml.stdout.exp \
+       threadname_xml.stderr.exp
 
 check_PROGRAMS = \
        accounting \
@@ -335,7 +338,8 @@ check_PROGRAMS = \
        wcs \
        xml1 \
        wrap1 wrap2 wrap3 wrap4 wrap5 wrap6 wrap7 wrap7so.so wrap8 \
-       writev1
+       writev1 \
+       threadname
 
 if DWARF4
 check_PROGRAMS += dw4
@@ -367,6 +371,7 @@ dw4_CFLAGS          = $(AM_CFLAGS) -gdwarf-4 -fdebug-types-section
 err_disable3_LDADD     = -lpthread
 err_disable4_LDADD     = -lpthread
 thread_alloca_LDADD     = -lpthread
+threadname_LDADD       = -lpthread
 
 error_counts_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
 
diff --git a/memcheck/tests/threadname.c b/memcheck/tests/threadname.c
new file mode 100644 (file)
index 0000000..2eabfd5
--- /dev/null
@@ -0,0 +1,80 @@
+//#define _GNU_SOURCE
+#include <stdio.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+static pthread_t children[3];
+
+void bad_things(int offset)
+{
+  char* m = malloc(sizeof(char)*offset);
+  m[offset] = 0;
+  free(m);
+}
+
+void* child_fn_2 ( void* arg )
+{
+  const char* threadname = "012345678901234";
+
+  pthread_setname_np(pthread_self(), threadname);
+
+  bad_things(4);
+
+  return NULL;
+}
+
+void* child_fn_1 ( void* arg )
+{
+  const char* threadname = "try1";
+  int r;
+
+  pthread_setname_np(pthread_self(), threadname);
+
+  bad_things(3);
+
+  r = pthread_create(&children[2], NULL, child_fn_2, NULL);
+  assert(!r);
+
+  r = pthread_join(children[2], NULL);
+  assert(!r);
+
+  return NULL;
+}
+
+void* child_fn_0 ( void* arg )
+{
+  int r;
+
+  bad_things(2);
+
+  r = pthread_create(&children[1], NULL, child_fn_1, NULL);
+  assert(!r);
+
+  r = pthread_join(children[1], NULL);
+  assert(!r);
+
+  return NULL;
+}
+
+int main(int argc, const char** argv)
+{
+  int r;
+
+  bad_things(1);
+
+  r = pthread_create(&children[0], NULL, child_fn_0, NULL);
+  assert(!r);
+
+  r = pthread_join(children[0], NULL);
+  assert(!r);
+  
+  bad_things(5);
+
+  return 0;
+}
+
diff --git a/memcheck/tests/threadname.stderr.exp b/memcheck/tests/threadname.stderr.exp
new file mode 100644 (file)
index 0000000..8ee6752
--- /dev/null
@@ -0,0 +1,50 @@
+Invalid write of size 1
+   at 0x........: bad_things (threadname.c:16)
+   by 0x........: main (threadname.c:68)
+ Address 0x........ is 0 bytes after a block of size 1 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: bad_things (threadname.c:15)
+   by 0x........: main (threadname.c:68)
+
+Thread 2:
+Invalid write of size 1
+   at 0x........: bad_things (threadname.c:16)
+   by 0x........: child_fn_0 (threadname.c:53)
+   ...
+ Address 0x........ is 0 bytes after a block of size 2 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: bad_things (threadname.c:15)
+   by 0x........: child_fn_0 (threadname.c:53)
+   ...
+
+Thread 3 try1:
+Invalid write of size 1
+   at 0x........: bad_things (threadname.c:16)
+   by 0x........: child_fn_1 (threadname.c:38)
+   ...
+ Address 0x........ is 0 bytes after a block of size 3 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: bad_things (threadname.c:15)
+   by 0x........: child_fn_1 (threadname.c:38)
+   ...
+
+Thread 4 012345678901234:
+Invalid write of size 1
+   at 0x........: bad_things (threadname.c:16)
+   by 0x........: child_fn_2 (threadname.c:26)
+   ...
+ Address 0x........ is 0 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: bad_things (threadname.c:15)
+   by 0x........: child_fn_2 (threadname.c:26)
+   ...
+
+Thread 1:
+Invalid write of size 1
+   at 0x........: bad_things (threadname.c:16)
+   by 0x........: main (threadname.c:76)
+ Address 0x........ is 0 bytes after a block of size 5 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: bad_things (threadname.c:15)
+   by 0x........: main (threadname.c:76)
+
diff --git a/memcheck/tests/threadname.vgtest b/memcheck/tests/threadname.vgtest
new file mode 100644 (file)
index 0000000..4cffb8e
--- /dev/null
@@ -0,0 +1,2 @@
+prog: threadname
+vgopts: -q
diff --git a/memcheck/tests/threadname_xml.stderr.exp b/memcheck/tests/threadname_xml.stderr.exp
new file mode 100644 (file)
index 0000000..7ecc850
--- /dev/null
@@ -0,0 +1,373 @@
+<?xml version="1.0"?>
+
+<valgrindoutput>
+
+<protocolversion>4</protocolversion>
+<protocoltool>memcheck</protocoltool>
+
+<preamble>
+  <line>...</line>
+  <line>...</line>
+  <line>...</line>
+  <line>...</line>
+</preamble>
+
+<pid>...</pid>
+<ppid>...</ppid>
+<tool>memcheck</tool>
+
+<args>
+  <vargv>...</vargv>
+  <argv>
+    <exe>./threadname</exe>
+  </argv>
+</args>
+
+<status>
+  <state>RUNNING</state>
+  <time>...</time>
+</status>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <kind>InvalidWrite</kind>
+  <what>Invalid write of size 1</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Address 0x........ is 0 bytes after a block of size 1 alloc'd</auxwhat>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>malloc</fn>
+      <dir>...</dir>
+      <file>vg_replace_malloc.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+</error>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <kind>InvalidWrite</kind>
+  <what>Invalid write of size 1</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_0</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Address 0x........ is 0 bytes after a block of size 2 alloc'd</auxwhat>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>malloc</fn>
+      <dir>...</dir>
+      <file>vg_replace_malloc.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_0</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+</error>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <threadname>try1</threadname>
+  <kind>InvalidWrite</kind>
+  <what>Invalid write of size 1</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_1</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Address 0x........ is 0 bytes after a block of size 3 alloc'd</auxwhat>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>malloc</fn>
+      <dir>...</dir>
+      <file>vg_replace_malloc.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_1</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+</error>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <threadname>012345678901234</threadname>
+  <kind>InvalidWrite</kind>
+  <what>Invalid write of size 1</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_2</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Address 0x........ is 0 bytes after a block of size 4 alloc'd</auxwhat>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>malloc</fn>
+      <dir>...</dir>
+      <file>vg_replace_malloc.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>child_fn_2</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>start_thread</fn>
+      <dir>...</dir>
+      <file>pthread_create.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+</error>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <kind>InvalidWrite</kind>
+  <what>Invalid write of size 1</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Address 0x........ is 0 bytes after a block of size 5 alloc'd</auxwhat>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>malloc</fn>
+      <dir>...</dir>
+      <file>vg_replace_malloc.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>bad_things</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>threadname.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+</error>
+
+
+<status>
+  <state>FINISHED</state>
+  <time>...</time>
+</status>
+
+<errorcounts>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+</errorcounts>
+
+<suppcounts>...</suppcounts>
+
+</valgrindoutput>
+
diff --git a/memcheck/tests/threadname_xml.vgtest b/memcheck/tests/threadname_xml.vgtest
new file mode 100644 (file)
index 0000000..730fe72
--- /dev/null
@@ -0,0 +1,3 @@
+prog: threadname
+vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
+stderr_filter: filter_xml