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; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits