[Lldb-commits] [lldb] r267133 - Renumber ThreadSanitizer-provided thread IDs to match LLDB thread numbers.

Kuba Brecka via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 22 03:40:15 PDT 2016


Author: kuba.brecka
Date: Fri Apr 22 05:40:14 2016
New Revision: 267133

URL: http://llvm.org/viewvc/llvm-project?rev=267133&view=rev
Log:
Renumber ThreadSanitizer-provided thread IDs to match LLDB thread numbers.


Added:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c
Modified:
    lldb/trunk/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile?rev=267133&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile Fri Apr 22 05:40:14 2016
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -fsanitize=thread -g
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py?rev=267133&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py Fri Apr 22 05:40:14 2016
@@ -0,0 +1,67 @@
+"""
+Tests that TSan and LLDB have correct thread numbers.
+"""
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+import json
+
+class TsanThreadNumbersTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @expectedFailureAll(oslist=["linux"], bugnumber="non-core functionality, need to reenable and fix later (DES 2014.11.07)")
+    @skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default
+    @skipIfRemote
+    @skipUnlessCompilerRt
+    def test (self):
+        self.build ()
+        self.tsan_tests ()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+    def tsan_tests (self):
+        exe = os.path.join (os.getcwd(), "a.out")
+        self.expect("file " + exe, patterns = [ "Current executable set to .*a.out" ])
+
+        self.runCmd("run")
+
+        stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason()
+        if stop_reason == lldb.eStopReasonExec:
+            # On OS X 10.10 and older, we need to re-exec to enable interceptors.
+            self.runCmd("continue")
+
+        # the stop reason of the thread should be breakpoint.
+        self.expect("thread list", "A data race should be detected",
+            substrs = ['stopped', 'stop reason = Data race detected'])
+
+        self.assertEqual(self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason(), lldb.eStopReasonInstrumentation)
+
+        report_thread_id = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetIndexID()
+
+        self.expect("thread info -s", "The extended stop info should contain the TSan provided fields",
+            substrs = ["instrumentation_class", "description", "mops"])
+
+        output_lines = self.res.GetOutput().split('\n')
+        json_line = '\n'.join(output_lines[2:])
+        data = json.loads(json_line)
+        self.assertEqual(data["instrumentation_class"], "ThreadSanitizer")
+        self.assertEqual(data["issue_type"], "data-race")
+        self.assertEqual(len(data["mops"]), 2)
+
+        self.assertEqual(data["mops"][0]["thread_id"], report_thread_id)
+
+        other_thread_id = data["mops"][1]["thread_id"]
+        self.assertTrue(other_thread_id != report_thread_id)
+        other_thread = self.dbg.GetSelectedTarget().process.GetThreadByIndexID(other_thread_id)
+        self.assertTrue(other_thread.IsValid())
+
+        self.runCmd("thread select %d" % other_thread_id)
+
+        self.expect("thread backtrace", "The other thread should be stopped in f1 or f2",
+            substrs = ["a.out", "main.c"])

Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c?rev=267133&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c Fri Apr 22 05:40:14 2016
@@ -0,0 +1,58 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+char *pointer;
+
+void *nothing(void *p) {
+    return NULL;
+}
+
+void *f1(void *p) {
+    pointer[0] = 'x';
+    sleep(100);
+    return NULL;
+}
+
+void *f2(void *p) {
+    pointer[0] = 'y';
+    sleep(100);
+    return NULL;
+}
+
+int main (int argc, char const *argv[])
+{
+    pointer = (char *)malloc(10);
+
+    for (int i = 0; i < 3; i++) {
+        pthread_t t;
+        pthread_create(&t, NULL, nothing, NULL);
+        pthread_join(t, NULL);
+    }
+
+    pthread_t t1;
+    pthread_create(&t1, NULL, f1, NULL);
+
+    for (int i = 0; i < 3; i++) {
+        pthread_t t;
+        pthread_create(&t, NULL, nothing, NULL);
+        pthread_join(t, NULL);
+    }
+
+    pthread_t t2;
+    pthread_create(&t2, NULL, f2, NULL);
+
+    pthread_join(t1, NULL);
+    pthread_join(t2, NULL);
+
+    return 0;
+}

Modified: lldb/trunk/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp?rev=267133&r1=267132&r2=267133&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp (original)
+++ lldb/trunk/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp Fri Apr 22 05:40:14 2016
@@ -150,7 +150,7 @@ extern "C"
                               unsigned long trace_size);
     int __tsan_get_report_mutex(void *report, unsigned long idx, unsigned long *mutex_id, void **addr,
                                 int *destroyed, void **trace, unsigned long trace_size);
-    int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *pid,
+    int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *os_id,
                                  int *running, const char **name, int *parent_tid,
                                  void **trace, unsigned long trace_size);
     int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid);
@@ -209,7 +209,7 @@ struct data {
     struct {
         int idx;
         int tid;
-        unsigned long pid;
+        unsigned long os_id;
         int running;
         const char *name;
         int parent_tid;
@@ -258,7 +258,7 @@ for (int i = 0; i < t.mutex_count; i++)
 if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE;
 for (int i = 0; i < t.thread_count; i++) {
     t.threads[i].idx = i;
-    __tsan_get_report_thread(t.report, i, &t.threads[i].tid, &t.threads[i].pid, &t.threads[i].running, &t.threads[i].name, &t.threads[i].parent_tid, t.threads[i].trace, REPORT_TRACE_SIZE);
+    __tsan_get_report_thread(t.report, i, &t.threads[i].tid, &t.threads[i].os_id, &t.threads[i].running, &t.threads[i].name, &t.threads[i].parent_tid, t.threads[i].trace, REPORT_TRACE_SIZE);
 }
 
 if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE;
@@ -310,6 +310,35 @@ RetrieveString(ValueObjectSP return_valu
     return str;
 }
 
+static void
+GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, std::map<uint64_t, user_id_t> &thread_id_map)
+{
+    ConvertToStructuredArray(data, ".threads", ".thread_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
+        uint64_t thread_id = o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0);
+        uint64_t thread_os_id = o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0);
+        user_id_t lldb_user_id = 0;
+        
+        bool can_update = true;
+        ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID(thread_os_id, can_update);
+        if (lldb_thread) {
+            lldb_user_id = lldb_thread->GetIndexID();
+        } else {
+            // This isn't a live thread anymore.  Ask process to assign a new Index ID (or return an old one if we've already seen this thread_os_id).
+            // It will also make sure that no new threads are assigned this Index ID.
+            lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id);
+        }
+        
+        thread_id_map[thread_id] = lldb_user_id;
+    });
+}
+
+static user_id_t Renumber(uint64_t id, std::map<uint64_t, user_id_t> &thread_id_map) {
+    if (! thread_id_map.count(id))
+        return 0;
+    
+    return thread_id_map[id];
+}
+
 StructuredData::ObjectSP
 ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref)
 {
@@ -346,6 +375,9 @@ ThreadSanitizerRuntime::RetrieveReportDa
         return StructuredData::ObjectSP();
     }
     
+    std::map<uint64_t, user_id_t> thread_id_map;
+    GetRenumberedThreadIds(process_sp, main_value, thread_id_map);
+    
     StructuredData::Dictionary *dict = new StructuredData::Dictionary();
     dict->AddStringItem("instrumentation_class", "ThreadSanitizer");
     dict->AddStringItem("issue_type", RetrieveString(main_value, process_sp, ".description"));
@@ -358,9 +390,9 @@ ThreadSanitizerRuntime::RetrieveReportDa
     });
     dict->AddItem("stacks", StructuredData::ObjectSP(stacks));
     
-    StructuredData::Array *mops = ConvertToStructuredArray(main_value, ".mops", ".mop_count", [] (ValueObjectSP o, StructuredData::Dictionary *dict) {
+    StructuredData::Array *mops = ConvertToStructuredArray(main_value, ".mops", ".mop_count", [&thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
-        dict->AddIntegerItem("thread_id", o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0));
+        dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
         dict->AddIntegerItem("size", o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0));
         dict->AddBooleanItem("is_write", o->GetValueForExpressionPath(".write")->GetValueAsUnsigned(0));
         dict->AddBooleanItem("is_atomic", o->GetValueForExpressionPath(".atomic")->GetValueAsUnsigned(0));
@@ -369,13 +401,13 @@ ThreadSanitizerRuntime::RetrieveReportDa
     });
     dict->AddItem("mops", StructuredData::ObjectSP(mops));
     
-    StructuredData::Array *locs = ConvertToStructuredArray(main_value, ".locs", ".loc_count", [process_sp] (ValueObjectSP o, StructuredData::Dictionary *dict) {
+    StructuredData::Array *locs = ConvertToStructuredArray(main_value, ".locs", ".loc_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
         dict->AddStringItem("type", RetrieveString(o, process_sp, ".type"));
         dict->AddIntegerItem("address", o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0));
         dict->AddIntegerItem("start", o->GetValueForExpressionPath(".start")->GetValueAsUnsigned(0));
         dict->AddIntegerItem("size", o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0));
-        dict->AddIntegerItem("thread_id", o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0));
+        dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
         dict->AddIntegerItem("file_descriptor", o->GetValueForExpressionPath(".fd")->GetValueAsUnsigned(0));
         dict->AddIntegerItem("suppressable", o->GetValueForExpressionPath(".suppressable")->GetValueAsUnsigned(0));
         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
@@ -391,20 +423,20 @@ ThreadSanitizerRuntime::RetrieveReportDa
     });
     dict->AddItem("mutexes", StructuredData::ObjectSP(mutexes));
     
-    StructuredData::Array *threads = ConvertToStructuredArray(main_value, ".threads", ".thread_count", [process_sp] (ValueObjectSP o, StructuredData::Dictionary *dict) {
+    StructuredData::Array *threads = ConvertToStructuredArray(main_value, ".threads", ".thread_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
-        dict->AddIntegerItem("thread_id", o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0));
-        dict->AddIntegerItem("process_id", o->GetValueForExpressionPath(".pid")->GetValueAsUnsigned(0));
+        dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
+        dict->AddIntegerItem("thread_os_id", o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0));
         dict->AddIntegerItem("running", o->GetValueForExpressionPath(".running")->GetValueAsUnsigned(0));
         dict->AddStringItem("name", RetrieveString(o, process_sp, ".name"));
-        dict->AddIntegerItem("parent_thread_id", o->GetValueForExpressionPath(".parent_tid")->GetValueAsUnsigned(0));
+        dict->AddIntegerItem("parent_thread_id", Renumber(o->GetValueForExpressionPath(".parent_tid")->GetValueAsUnsigned(0), thread_id_map));
         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
     });
     dict->AddItem("threads", StructuredData::ObjectSP(threads));
     
-    StructuredData::Array *unique_tids = ConvertToStructuredArray(main_value, ".unique_tids", ".unique_tid_count", [] (ValueObjectSP o, StructuredData::Dictionary *dict) {
+    StructuredData::Array *unique_tids = ConvertToStructuredArray(main_value, ".unique_tids", ".unique_tid_count", [&thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
-        dict->AddIntegerItem("tid", o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0));
+        dict->AddIntegerItem("tid", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
     });
     dict->AddItem("unique_tids", StructuredData::ObjectSP(unique_tids));
     
@@ -697,9 +729,7 @@ GenerateThreadName(std::string path, Str
     
     if (path == "threads") {
         int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue();
-        int parent_thread_id = o->GetObjectForDotSeparatedPath("parent_thread_id")->GetIntegerValue();
-        
-        result = Sprintf("thread %d created by thread %d at", thread_id, parent_thread_id);
+        result = Sprintf("thread %d created at", thread_id);
     }
     
     if (path == "locs") {
@@ -741,7 +771,7 @@ AddThreadsForPath(std::string path, Thre
         if (pcs.size() == 0)
             return true;
         
-        StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_id");
+        StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id");
         tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
         
         uint32_t stop_id = 0;




More information about the lldb-commits mailing list