15ffd83dbSDimitry Andric //===-- InstrumentationRuntimeTSan.cpp ------------------------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "InstrumentationRuntimeTSan.h" 105ffd83dbSDimitry Andric 115ffd83dbSDimitry Andric #include "Plugins/Process/Utility/HistoryThread.h" 125ffd83dbSDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h" 135ffd83dbSDimitry Andric #include "lldb/Core/Debugger.h" 145ffd83dbSDimitry Andric #include "lldb/Core/Module.h" 155ffd83dbSDimitry Andric #include "lldb/Core/PluginInterface.h" 165ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h" 175ffd83dbSDimitry Andric #include "lldb/Core/ValueObject.h" 185ffd83dbSDimitry Andric #include "lldb/Expression/UserExpression.h" 195f757f3fSDimitry Andric #include "lldb/Host/StreamFile.h" 205ffd83dbSDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 215ffd83dbSDimitry Andric #include "lldb/Symbol/Symbol.h" 225ffd83dbSDimitry Andric #include "lldb/Symbol/SymbolContext.h" 235ffd83dbSDimitry Andric #include "lldb/Symbol/Variable.h" 245ffd83dbSDimitry Andric #include "lldb/Symbol/VariableList.h" 255ffd83dbSDimitry Andric #include "lldb/Target/InstrumentationRuntimeStopInfo.h" 265ffd83dbSDimitry Andric #include "lldb/Target/SectionLoadList.h" 275ffd83dbSDimitry Andric #include "lldb/Target/StopInfo.h" 285ffd83dbSDimitry Andric #include "lldb/Target/Target.h" 295ffd83dbSDimitry Andric #include "lldb/Target/Thread.h" 305ffd83dbSDimitry Andric #include "lldb/Utility/RegularExpression.h" 315ffd83dbSDimitry Andric #include "lldb/Utility/Stream.h" 325ffd83dbSDimitry Andric 335ffd83dbSDimitry Andric #include <memory> 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric using namespace lldb; 365ffd83dbSDimitry Andric using namespace lldb_private; 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(InstrumentationRuntimeTSan) 395ffd83dbSDimitry Andric 405ffd83dbSDimitry Andric lldb::InstrumentationRuntimeSP 415ffd83dbSDimitry Andric InstrumentationRuntimeTSan::CreateInstance(const lldb::ProcessSP &process_sp) { 425ffd83dbSDimitry Andric return InstrumentationRuntimeSP(new InstrumentationRuntimeTSan(process_sp)); 435ffd83dbSDimitry Andric } 445ffd83dbSDimitry Andric 455ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Initialize() { 465ffd83dbSDimitry Andric PluginManager::RegisterPlugin( 475ffd83dbSDimitry Andric GetPluginNameStatic(), "ThreadSanitizer instrumentation runtime plugin.", 485ffd83dbSDimitry Andric CreateInstance, GetTypeStatic); 495ffd83dbSDimitry Andric } 505ffd83dbSDimitry Andric 515ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Terminate() { 525ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 535ffd83dbSDimitry Andric } 545ffd83dbSDimitry Andric 555ffd83dbSDimitry Andric lldb::InstrumentationRuntimeType InstrumentationRuntimeTSan::GetTypeStatic() { 565ffd83dbSDimitry Andric return eInstrumentationRuntimeTypeThreadSanitizer; 575ffd83dbSDimitry Andric } 585ffd83dbSDimitry Andric 595ffd83dbSDimitry Andric InstrumentationRuntimeTSan::~InstrumentationRuntimeTSan() { Deactivate(); } 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric const char *thread_sanitizer_retrieve_report_data_prefix = R"( 625ffd83dbSDimitry Andric extern "C" 635ffd83dbSDimitry Andric { 645ffd83dbSDimitry Andric void *__tsan_get_current_report(); 655ffd83dbSDimitry Andric int __tsan_get_report_data(void *report, const char **description, int *count, 665ffd83dbSDimitry Andric int *stack_count, int *mop_count, int *loc_count, 675ffd83dbSDimitry Andric int *mutex_count, int *thread_count, 685ffd83dbSDimitry Andric int *unique_tid_count, void **sleep_trace, 695ffd83dbSDimitry Andric unsigned long trace_size); 705ffd83dbSDimitry Andric int __tsan_get_report_stack(void *report, unsigned long idx, void **trace, 715ffd83dbSDimitry Andric unsigned long trace_size); 725ffd83dbSDimitry Andric int __tsan_get_report_mop(void *report, unsigned long idx, int *tid, void **addr, 735ffd83dbSDimitry Andric int *size, int *write, int *atomic, void **trace, 745ffd83dbSDimitry Andric unsigned long trace_size); 755ffd83dbSDimitry Andric int __tsan_get_report_loc(void *report, unsigned long idx, const char **type, 765ffd83dbSDimitry Andric void **addr, unsigned long *start, unsigned long *size, int *tid, 775ffd83dbSDimitry Andric int *fd, int *suppressable, void **trace, 785ffd83dbSDimitry Andric unsigned long trace_size); 795ffd83dbSDimitry Andric int __tsan_get_report_mutex(void *report, unsigned long idx, unsigned long *mutex_id, void **addr, 805ffd83dbSDimitry Andric int *destroyed, void **trace, unsigned long trace_size); 815ffd83dbSDimitry Andric int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *os_id, 825ffd83dbSDimitry Andric int *running, const char **name, int *parent_tid, 835ffd83dbSDimitry Andric void **trace, unsigned long trace_size); 845ffd83dbSDimitry Andric int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid); 855ffd83dbSDimitry Andric 865ffd83dbSDimitry Andric // TODO: dlsym won't work on Windows. 875ffd83dbSDimitry Andric void *dlsym(void* handle, const char* symbol); 885ffd83dbSDimitry Andric int (*ptr__tsan_get_report_loc_object_type)(void *report, unsigned long idx, const char **object_type); 895ffd83dbSDimitry Andric } 9006c3fb27SDimitry Andric )"; 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric const char *thread_sanitizer_retrieve_report_data_command = R"( 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric const int REPORT_TRACE_SIZE = 128; 955ffd83dbSDimitry Andric const int REPORT_ARRAY_SIZE = 4; 965ffd83dbSDimitry Andric 9706c3fb27SDimitry Andric struct { 985ffd83dbSDimitry Andric void *report; 995ffd83dbSDimitry Andric const char *description; 1005ffd83dbSDimitry Andric int report_count; 1015ffd83dbSDimitry Andric 1025ffd83dbSDimitry Andric void *sleep_trace[REPORT_TRACE_SIZE]; 1035ffd83dbSDimitry Andric 1045ffd83dbSDimitry Andric int stack_count; 1055ffd83dbSDimitry Andric struct { 1065ffd83dbSDimitry Andric int idx; 1075ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1085ffd83dbSDimitry Andric } stacks[REPORT_ARRAY_SIZE]; 1095ffd83dbSDimitry Andric 1105ffd83dbSDimitry Andric int mop_count; 1115ffd83dbSDimitry Andric struct { 1125ffd83dbSDimitry Andric int idx; 1135ffd83dbSDimitry Andric int tid; 1145ffd83dbSDimitry Andric int size; 1155ffd83dbSDimitry Andric int write; 1165ffd83dbSDimitry Andric int atomic; 1175ffd83dbSDimitry Andric void *addr; 1185ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1195ffd83dbSDimitry Andric } mops[REPORT_ARRAY_SIZE]; 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric int loc_count; 1225ffd83dbSDimitry Andric struct { 1235ffd83dbSDimitry Andric int idx; 1245ffd83dbSDimitry Andric const char *type; 1255ffd83dbSDimitry Andric void *addr; 1265ffd83dbSDimitry Andric unsigned long start; 1275ffd83dbSDimitry Andric unsigned long size; 1285ffd83dbSDimitry Andric int tid; 1295ffd83dbSDimitry Andric int fd; 1305ffd83dbSDimitry Andric int suppressable; 1315ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1325ffd83dbSDimitry Andric const char *object_type; 1335ffd83dbSDimitry Andric } locs[REPORT_ARRAY_SIZE]; 1345ffd83dbSDimitry Andric 1355ffd83dbSDimitry Andric int mutex_count; 1365ffd83dbSDimitry Andric struct { 1375ffd83dbSDimitry Andric int idx; 1385ffd83dbSDimitry Andric unsigned long mutex_id; 1395ffd83dbSDimitry Andric void *addr; 1405ffd83dbSDimitry Andric int destroyed; 1415ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1425ffd83dbSDimitry Andric } mutexes[REPORT_ARRAY_SIZE]; 1435ffd83dbSDimitry Andric 1445ffd83dbSDimitry Andric int thread_count; 1455ffd83dbSDimitry Andric struct { 1465ffd83dbSDimitry Andric int idx; 1475ffd83dbSDimitry Andric int tid; 1485ffd83dbSDimitry Andric unsigned long os_id; 1495ffd83dbSDimitry Andric int running; 1505ffd83dbSDimitry Andric const char *name; 1515ffd83dbSDimitry Andric int parent_tid; 1525ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1535ffd83dbSDimitry Andric } threads[REPORT_ARRAY_SIZE]; 1545ffd83dbSDimitry Andric 1555ffd83dbSDimitry Andric int unique_tid_count; 1565ffd83dbSDimitry Andric struct { 1575ffd83dbSDimitry Andric int idx; 1585ffd83dbSDimitry Andric int tid; 1595ffd83dbSDimitry Andric } unique_tids[REPORT_ARRAY_SIZE]; 16006c3fb27SDimitry Andric } t = {0}; 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric ptr__tsan_get_report_loc_object_type = (typeof(ptr__tsan_get_report_loc_object_type))(void *)dlsym((void*)-2 /*RTLD_DEFAULT*/, "__tsan_get_report_loc_object_type"); 1635ffd83dbSDimitry Andric 1645ffd83dbSDimitry Andric t.report = __tsan_get_current_report(); 1655ffd83dbSDimitry Andric __tsan_get_report_data(t.report, &t.description, &t.report_count, &t.stack_count, &t.mop_count, &t.loc_count, &t.mutex_count, &t.thread_count, &t.unique_tid_count, t.sleep_trace, REPORT_TRACE_SIZE); 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric if (t.stack_count > REPORT_ARRAY_SIZE) t.stack_count = REPORT_ARRAY_SIZE; 1685ffd83dbSDimitry Andric for (int i = 0; i < t.stack_count; i++) { 1695ffd83dbSDimitry Andric t.stacks[i].idx = i; 1705ffd83dbSDimitry Andric __tsan_get_report_stack(t.report, i, t.stacks[i].trace, REPORT_TRACE_SIZE); 1715ffd83dbSDimitry Andric } 1725ffd83dbSDimitry Andric 1735ffd83dbSDimitry Andric if (t.mop_count > REPORT_ARRAY_SIZE) t.mop_count = REPORT_ARRAY_SIZE; 1745ffd83dbSDimitry Andric for (int i = 0; i < t.mop_count; i++) { 1755ffd83dbSDimitry Andric t.mops[i].idx = i; 1765ffd83dbSDimitry Andric __tsan_get_report_mop(t.report, i, &t.mops[i].tid, &t.mops[i].addr, &t.mops[i].size, &t.mops[i].write, &t.mops[i].atomic, t.mops[i].trace, REPORT_TRACE_SIZE); 1775ffd83dbSDimitry Andric } 1785ffd83dbSDimitry Andric 1795ffd83dbSDimitry Andric if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE; 1805ffd83dbSDimitry Andric for (int i = 0; i < t.loc_count; i++) { 1815ffd83dbSDimitry Andric t.locs[i].idx = i; 1825ffd83dbSDimitry Andric __tsan_get_report_loc(t.report, i, &t.locs[i].type, &t.locs[i].addr, &t.locs[i].start, &t.locs[i].size, &t.locs[i].tid, &t.locs[i].fd, &t.locs[i].suppressable, t.locs[i].trace, REPORT_TRACE_SIZE); 1835ffd83dbSDimitry Andric if (ptr__tsan_get_report_loc_object_type) 1845ffd83dbSDimitry Andric ptr__tsan_get_report_loc_object_type(t.report, i, &t.locs[i].object_type); 1855ffd83dbSDimitry Andric } 1865ffd83dbSDimitry Andric 1875ffd83dbSDimitry Andric if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE; 1885ffd83dbSDimitry Andric for (int i = 0; i < t.mutex_count; i++) { 1895ffd83dbSDimitry Andric t.mutexes[i].idx = i; 1905ffd83dbSDimitry Andric __tsan_get_report_mutex(t.report, i, &t.mutexes[i].mutex_id, &t.mutexes[i].addr, &t.mutexes[i].destroyed, t.mutexes[i].trace, REPORT_TRACE_SIZE); 1915ffd83dbSDimitry Andric } 1925ffd83dbSDimitry Andric 1935ffd83dbSDimitry Andric if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE; 1945ffd83dbSDimitry Andric for (int i = 0; i < t.thread_count; i++) { 1955ffd83dbSDimitry Andric t.threads[i].idx = i; 1965ffd83dbSDimitry Andric __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); 1975ffd83dbSDimitry Andric } 1985ffd83dbSDimitry Andric 1995ffd83dbSDimitry Andric if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE; 2005ffd83dbSDimitry Andric for (int i = 0; i < t.unique_tid_count; i++) { 2015ffd83dbSDimitry Andric t.unique_tids[i].idx = i; 2025ffd83dbSDimitry Andric __tsan_get_report_unique_tid(t.report, i, &t.unique_tids[i].tid); 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric 2055ffd83dbSDimitry Andric t; 2065ffd83dbSDimitry Andric )"; 2075ffd83dbSDimitry Andric 208bdd1243dSDimitry Andric static StructuredData::ArraySP 2095ffd83dbSDimitry Andric CreateStackTrace(ValueObjectSP o, 2105ffd83dbSDimitry Andric const std::string &trace_item_name = ".trace") { 211bdd1243dSDimitry Andric auto trace_sp = std::make_shared<StructuredData::Array>(); 2125ffd83dbSDimitry Andric ValueObjectSP trace_value_object = 2135ffd83dbSDimitry Andric o->GetValueForExpressionPath(trace_item_name.c_str()); 2145ffd83dbSDimitry Andric size_t count = trace_value_object->GetNumChildren(); 2155ffd83dbSDimitry Andric for (size_t j = 0; j < count; j++) { 2165ffd83dbSDimitry Andric addr_t trace_addr = 21706c3fb27SDimitry Andric trace_value_object->GetChildAtIndex(j)->GetValueAsUnsigned(0); 2185ffd83dbSDimitry Andric if (trace_addr == 0) 2195ffd83dbSDimitry Andric break; 22006c3fb27SDimitry Andric trace_sp->AddIntegerItem(trace_addr); 2215ffd83dbSDimitry Andric } 222bdd1243dSDimitry Andric return trace_sp; 2235ffd83dbSDimitry Andric } 2245ffd83dbSDimitry Andric 225bdd1243dSDimitry Andric static StructuredData::ArraySP ConvertToStructuredArray( 2265ffd83dbSDimitry Andric ValueObjectSP return_value_sp, const std::string &items_name, 2275ffd83dbSDimitry Andric const std::string &count_name, 228bdd1243dSDimitry Andric std::function<void(const ValueObjectSP &o, 229bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict)> const 2305ffd83dbSDimitry Andric &callback) { 231bdd1243dSDimitry Andric auto array_sp = std::make_shared<StructuredData::Array>(); 2325ffd83dbSDimitry Andric unsigned int count = 2335ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(count_name.c_str()) 2345ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2355ffd83dbSDimitry Andric ValueObjectSP objects = 2365ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(items_name.c_str()); 2375ffd83dbSDimitry Andric for (unsigned int i = 0; i < count; i++) { 23806c3fb27SDimitry Andric ValueObjectSP o = objects->GetChildAtIndex(i); 239bdd1243dSDimitry Andric auto dict_sp = std::make_shared<StructuredData::Dictionary>(); 2405ffd83dbSDimitry Andric 241bdd1243dSDimitry Andric callback(o, dict_sp); 2425ffd83dbSDimitry Andric 243bdd1243dSDimitry Andric array_sp->AddItem(dict_sp); 2445ffd83dbSDimitry Andric } 245bdd1243dSDimitry Andric return array_sp; 2465ffd83dbSDimitry Andric } 2475ffd83dbSDimitry Andric 2485ffd83dbSDimitry Andric static std::string RetrieveString(ValueObjectSP return_value_sp, 2495ffd83dbSDimitry Andric ProcessSP process_sp, 2505ffd83dbSDimitry Andric const std::string &expression_path) { 2515ffd83dbSDimitry Andric addr_t ptr = 2525ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(expression_path.c_str()) 2535ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2545ffd83dbSDimitry Andric std::string str; 2555ffd83dbSDimitry Andric Status error; 2565ffd83dbSDimitry Andric process_sp->ReadCStringFromMemory(ptr, str, error); 2575ffd83dbSDimitry Andric return str; 2585ffd83dbSDimitry Andric } 2595ffd83dbSDimitry Andric 2605ffd83dbSDimitry Andric static void 2615ffd83dbSDimitry Andric GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, 2625ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2635ffd83dbSDimitry Andric ConvertToStructuredArray( 2645ffd83dbSDimitry Andric data, ".threads", ".thread_count", 265bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 266bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 2675ffd83dbSDimitry Andric uint64_t thread_id = 2685ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0); 2695ffd83dbSDimitry Andric uint64_t thread_os_id = 2705ffd83dbSDimitry Andric o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0); 2715ffd83dbSDimitry Andric user_id_t lldb_user_id = 0; 2725ffd83dbSDimitry Andric 2735ffd83dbSDimitry Andric bool can_update = true; 2745ffd83dbSDimitry Andric ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID( 2755ffd83dbSDimitry Andric thread_os_id, can_update); 2765ffd83dbSDimitry Andric if (lldb_thread) { 2775ffd83dbSDimitry Andric lldb_user_id = lldb_thread->GetIndexID(); 2785ffd83dbSDimitry Andric } else { 2795ffd83dbSDimitry Andric // This isn't a live thread anymore. Ask process to assign a new 2805ffd83dbSDimitry Andric // Index ID (or return an old one if we've already seen this 2815ffd83dbSDimitry Andric // thread_os_id). It will also make sure that no new threads are 2825ffd83dbSDimitry Andric // assigned this Index ID. 2835ffd83dbSDimitry Andric lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id); 2845ffd83dbSDimitry Andric } 2855ffd83dbSDimitry Andric 2865ffd83dbSDimitry Andric thread_id_map[thread_id] = lldb_user_id; 2875ffd83dbSDimitry Andric }); 2885ffd83dbSDimitry Andric } 2895ffd83dbSDimitry Andric 2905ffd83dbSDimitry Andric static user_id_t Renumber(uint64_t id, 2915ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2925ffd83dbSDimitry Andric auto IT = thread_id_map.find(id); 2935ffd83dbSDimitry Andric if (IT == thread_id_map.end()) 2945ffd83dbSDimitry Andric return 0; 2955ffd83dbSDimitry Andric 2965ffd83dbSDimitry Andric return IT->second; 2975ffd83dbSDimitry Andric } 2985ffd83dbSDimitry Andric 2995ffd83dbSDimitry Andric StructuredData::ObjectSP InstrumentationRuntimeTSan::RetrieveReportData( 3005ffd83dbSDimitry Andric ExecutionContextRef exe_ctx_ref) { 3015ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 3025ffd83dbSDimitry Andric if (!process_sp) 3035ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3045ffd83dbSDimitry Andric 3055ffd83dbSDimitry Andric ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); 30606c3fb27SDimitry Andric StackFrameSP frame_sp = 30706c3fb27SDimitry Andric thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); 3085ffd83dbSDimitry Andric 3095ffd83dbSDimitry Andric if (!frame_sp) 3105ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3115ffd83dbSDimitry Andric 3125ffd83dbSDimitry Andric EvaluateExpressionOptions options; 3135ffd83dbSDimitry Andric options.SetUnwindOnError(true); 3145ffd83dbSDimitry Andric options.SetTryAllThreads(true); 3155ffd83dbSDimitry Andric options.SetStopOthers(true); 3165ffd83dbSDimitry Andric options.SetIgnoreBreakpoints(true); 3175ffd83dbSDimitry Andric options.SetTimeout(process_sp->GetUtilityExpressionTimeout()); 3185ffd83dbSDimitry Andric options.SetPrefix(thread_sanitizer_retrieve_report_data_prefix); 3195ffd83dbSDimitry Andric options.SetAutoApplyFixIts(false); 3205ffd83dbSDimitry Andric options.SetLanguage(eLanguageTypeObjC_plus_plus); 3215ffd83dbSDimitry Andric 3225ffd83dbSDimitry Andric ValueObjectSP main_value; 3235ffd83dbSDimitry Andric ExecutionContext exe_ctx; 3245ffd83dbSDimitry Andric Status eval_error; 3255ffd83dbSDimitry Andric frame_sp->CalculateExecutionContext(exe_ctx); 3265ffd83dbSDimitry Andric ExpressionResults result = UserExpression::Evaluate( 3275ffd83dbSDimitry Andric exe_ctx, options, thread_sanitizer_retrieve_report_data_command, "", 3285ffd83dbSDimitry Andric main_value, eval_error); 3295ffd83dbSDimitry Andric if (result != eExpressionCompleted) { 33081ad6265SDimitry Andric StreamString ss; 33181ad6265SDimitry Andric ss << "cannot evaluate ThreadSanitizer expression:\n"; 33281ad6265SDimitry Andric ss << eval_error.AsCString(); 33381ad6265SDimitry Andric Debugger::ReportWarning(ss.GetString().str(), 33481ad6265SDimitry Andric process_sp->GetTarget().GetDebugger().GetID()); 3355ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3365ffd83dbSDimitry Andric } 3375ffd83dbSDimitry Andric 3385ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> thread_id_map; 3395ffd83dbSDimitry Andric GetRenumberedThreadIds(process_sp, main_value, thread_id_map); 3405ffd83dbSDimitry Andric 341bdd1243dSDimitry Andric auto dict = std::make_shared<StructuredData::Dictionary>(); 3425ffd83dbSDimitry Andric dict->AddStringItem("instrumentation_class", "ThreadSanitizer"); 3435ffd83dbSDimitry Andric dict->AddStringItem("issue_type", 3445ffd83dbSDimitry Andric RetrieveString(main_value, process_sp, ".description")); 3455ffd83dbSDimitry Andric dict->AddIntegerItem("report_count", 3465ffd83dbSDimitry Andric main_value->GetValueForExpressionPath(".report_count") 3475ffd83dbSDimitry Andric ->GetValueAsUnsigned(0)); 348bdd1243dSDimitry Andric dict->AddItem("sleep_trace", CreateStackTrace( 349bdd1243dSDimitry Andric main_value, ".sleep_trace")); 3505ffd83dbSDimitry Andric 351bdd1243dSDimitry Andric StructuredData::ArraySP stacks = ConvertToStructuredArray( 3525ffd83dbSDimitry Andric main_value, ".stacks", ".stack_count", 353bdd1243dSDimitry Andric [thread_sp](const ValueObjectSP &o, 354bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3555ffd83dbSDimitry Andric dict->AddIntegerItem( 3565ffd83dbSDimitry Andric "index", 3575ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 358bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 3595ffd83dbSDimitry Andric // "stacks" happen on the current thread 3605ffd83dbSDimitry Andric dict->AddIntegerItem("thread_id", thread_sp->GetIndexID()); 3615ffd83dbSDimitry Andric }); 362bdd1243dSDimitry Andric dict->AddItem("stacks", stacks); 3635ffd83dbSDimitry Andric 364bdd1243dSDimitry Andric StructuredData::ArraySP mops = ConvertToStructuredArray( 3655ffd83dbSDimitry Andric main_value, ".mops", ".mop_count", 366bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 367bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3685ffd83dbSDimitry Andric dict->AddIntegerItem( 3695ffd83dbSDimitry Andric "index", 3705ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 3715ffd83dbSDimitry Andric dict->AddIntegerItem( 3725ffd83dbSDimitry Andric "thread_id", 3735ffd83dbSDimitry Andric Renumber( 3745ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 3755ffd83dbSDimitry Andric thread_id_map)); 3765ffd83dbSDimitry Andric dict->AddIntegerItem( 3775ffd83dbSDimitry Andric "size", 3785ffd83dbSDimitry Andric o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0)); 3795ffd83dbSDimitry Andric dict->AddBooleanItem( 3805ffd83dbSDimitry Andric "is_write", 3815ffd83dbSDimitry Andric o->GetValueForExpressionPath(".write")->GetValueAsUnsigned(0)); 3825ffd83dbSDimitry Andric dict->AddBooleanItem( 3835ffd83dbSDimitry Andric "is_atomic", 3845ffd83dbSDimitry Andric o->GetValueForExpressionPath(".atomic")->GetValueAsUnsigned(0)); 3855ffd83dbSDimitry Andric dict->AddIntegerItem( 3865ffd83dbSDimitry Andric "address", 3875ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 388bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 3895ffd83dbSDimitry Andric }); 390bdd1243dSDimitry Andric dict->AddItem("mops", mops); 3915ffd83dbSDimitry Andric 392bdd1243dSDimitry Andric StructuredData::ArraySP locs = ConvertToStructuredArray( 3935ffd83dbSDimitry Andric main_value, ".locs", ".loc_count", 394bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 395bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3965ffd83dbSDimitry Andric dict->AddIntegerItem( 3975ffd83dbSDimitry Andric "index", 3985ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 3995ffd83dbSDimitry Andric dict->AddStringItem("type", RetrieveString(o, process_sp, ".type")); 4005ffd83dbSDimitry Andric dict->AddIntegerItem( 4015ffd83dbSDimitry Andric "address", 4025ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 4035ffd83dbSDimitry Andric dict->AddIntegerItem( 4045ffd83dbSDimitry Andric "start", 4055ffd83dbSDimitry Andric o->GetValueForExpressionPath(".start")->GetValueAsUnsigned(0)); 4065ffd83dbSDimitry Andric dict->AddIntegerItem( 4075ffd83dbSDimitry Andric "size", 4085ffd83dbSDimitry Andric o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0)); 4095ffd83dbSDimitry Andric dict->AddIntegerItem( 4105ffd83dbSDimitry Andric "thread_id", 4115ffd83dbSDimitry Andric Renumber( 4125ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4135ffd83dbSDimitry Andric thread_id_map)); 4145ffd83dbSDimitry Andric dict->AddIntegerItem( 4155ffd83dbSDimitry Andric "file_descriptor", 4165ffd83dbSDimitry Andric o->GetValueForExpressionPath(".fd")->GetValueAsUnsigned(0)); 4175ffd83dbSDimitry Andric dict->AddIntegerItem("suppressable", 4185ffd83dbSDimitry Andric o->GetValueForExpressionPath(".suppressable") 4195ffd83dbSDimitry Andric ->GetValueAsUnsigned(0)); 420bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4215ffd83dbSDimitry Andric dict->AddStringItem("object_type", 4225ffd83dbSDimitry Andric RetrieveString(o, process_sp, ".object_type")); 4235ffd83dbSDimitry Andric }); 424bdd1243dSDimitry Andric dict->AddItem("locs", locs); 4255ffd83dbSDimitry Andric 426bdd1243dSDimitry Andric StructuredData::ArraySP mutexes = ConvertToStructuredArray( 4275ffd83dbSDimitry Andric main_value, ".mutexes", ".mutex_count", 428bdd1243dSDimitry Andric [](const ValueObjectSP &o, const StructuredData::DictionarySP &dict) { 4295ffd83dbSDimitry Andric dict->AddIntegerItem( 4305ffd83dbSDimitry Andric "index", 4315ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4325ffd83dbSDimitry Andric dict->AddIntegerItem( 4335ffd83dbSDimitry Andric "mutex_id", 4345ffd83dbSDimitry Andric o->GetValueForExpressionPath(".mutex_id")->GetValueAsUnsigned(0)); 4355ffd83dbSDimitry Andric dict->AddIntegerItem( 4365ffd83dbSDimitry Andric "address", 4375ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 4385ffd83dbSDimitry Andric dict->AddIntegerItem( 4395ffd83dbSDimitry Andric "destroyed", 4405ffd83dbSDimitry Andric o->GetValueForExpressionPath(".destroyed")->GetValueAsUnsigned(0)); 441bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4425ffd83dbSDimitry Andric }); 443bdd1243dSDimitry Andric dict->AddItem("mutexes", mutexes); 4445ffd83dbSDimitry Andric 445bdd1243dSDimitry Andric StructuredData::ArraySP threads = ConvertToStructuredArray( 4465ffd83dbSDimitry Andric main_value, ".threads", ".thread_count", 447bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 448bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 4495ffd83dbSDimitry Andric dict->AddIntegerItem( 4505ffd83dbSDimitry Andric "index", 4515ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4525ffd83dbSDimitry Andric dict->AddIntegerItem( 4535ffd83dbSDimitry Andric "thread_id", 4545ffd83dbSDimitry Andric Renumber( 4555ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4565ffd83dbSDimitry Andric thread_id_map)); 4575ffd83dbSDimitry Andric dict->AddIntegerItem( 4585ffd83dbSDimitry Andric "thread_os_id", 4595ffd83dbSDimitry Andric o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0)); 4605ffd83dbSDimitry Andric dict->AddIntegerItem( 4615ffd83dbSDimitry Andric "running", 4625ffd83dbSDimitry Andric o->GetValueForExpressionPath(".running")->GetValueAsUnsigned(0)); 4635ffd83dbSDimitry Andric dict->AddStringItem("name", RetrieveString(o, process_sp, ".name")); 4645ffd83dbSDimitry Andric dict->AddIntegerItem( 4655ffd83dbSDimitry Andric "parent_thread_id", 4665ffd83dbSDimitry Andric Renumber(o->GetValueForExpressionPath(".parent_tid") 4675ffd83dbSDimitry Andric ->GetValueAsUnsigned(0), 4685ffd83dbSDimitry Andric thread_id_map)); 469bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4705ffd83dbSDimitry Andric }); 471bdd1243dSDimitry Andric dict->AddItem("threads", threads); 4725ffd83dbSDimitry Andric 473bdd1243dSDimitry Andric StructuredData::ArraySP unique_tids = ConvertToStructuredArray( 4745ffd83dbSDimitry Andric main_value, ".unique_tids", ".unique_tid_count", 475bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 476bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 4775ffd83dbSDimitry Andric dict->AddIntegerItem( 4785ffd83dbSDimitry Andric "index", 4795ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4805ffd83dbSDimitry Andric dict->AddIntegerItem( 4815ffd83dbSDimitry Andric "tid", 4825ffd83dbSDimitry Andric Renumber( 4835ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4845ffd83dbSDimitry Andric thread_id_map)); 4855ffd83dbSDimitry Andric }); 486bdd1243dSDimitry Andric dict->AddItem("unique_tids", unique_tids); 4875ffd83dbSDimitry Andric 488bdd1243dSDimitry Andric return dict; 4895ffd83dbSDimitry Andric } 4905ffd83dbSDimitry Andric 4915ffd83dbSDimitry Andric std::string 4925ffd83dbSDimitry Andric InstrumentationRuntimeTSan::FormatDescription(StructuredData::ObjectSP report) { 4935ffd83dbSDimitry Andric std::string description = std::string(report->GetAsDictionary() 4945ffd83dbSDimitry Andric ->GetValueForKey("issue_type") 4955ffd83dbSDimitry Andric ->GetAsString() 4965ffd83dbSDimitry Andric ->GetValue()); 4975ffd83dbSDimitry Andric 4985ffd83dbSDimitry Andric if (description == "data-race") { 4995ffd83dbSDimitry Andric return "Data race"; 5005ffd83dbSDimitry Andric } else if (description == "data-race-vptr") { 5015ffd83dbSDimitry Andric return "Data race on C++ virtual pointer"; 5025ffd83dbSDimitry Andric } else if (description == "heap-use-after-free") { 5035ffd83dbSDimitry Andric return "Use of deallocated memory"; 5045ffd83dbSDimitry Andric } else if (description == "heap-use-after-free-vptr") { 5055ffd83dbSDimitry Andric return "Use of deallocated C++ virtual pointer"; 5065ffd83dbSDimitry Andric } else if (description == "thread-leak") { 5075ffd83dbSDimitry Andric return "Thread leak"; 5085ffd83dbSDimitry Andric } else if (description == "locked-mutex-destroy") { 5095ffd83dbSDimitry Andric return "Destruction of a locked mutex"; 5105ffd83dbSDimitry Andric } else if (description == "mutex-double-lock") { 5115ffd83dbSDimitry Andric return "Double lock of a mutex"; 5125ffd83dbSDimitry Andric } else if (description == "mutex-invalid-access") { 5135ffd83dbSDimitry Andric return "Use of an uninitialized or destroyed mutex"; 5145ffd83dbSDimitry Andric } else if (description == "mutex-bad-unlock") { 5155ffd83dbSDimitry Andric return "Unlock of an unlocked mutex (or by a wrong thread)"; 5165ffd83dbSDimitry Andric } else if (description == "mutex-bad-read-lock") { 5175ffd83dbSDimitry Andric return "Read lock of a write locked mutex"; 5185ffd83dbSDimitry Andric } else if (description == "mutex-bad-read-unlock") { 5195ffd83dbSDimitry Andric return "Read unlock of a write locked mutex"; 5205ffd83dbSDimitry Andric } else if (description == "signal-unsafe-call") { 5215ffd83dbSDimitry Andric return "Signal-unsafe call inside a signal handler"; 5225ffd83dbSDimitry Andric } else if (description == "errno-in-signal-handler") { 5235ffd83dbSDimitry Andric return "Overwrite of errno in a signal handler"; 5245ffd83dbSDimitry Andric } else if (description == "lock-order-inversion") { 5255ffd83dbSDimitry Andric return "Lock order inversion (potential deadlock)"; 5265ffd83dbSDimitry Andric } else if (description == "external-race") { 5275ffd83dbSDimitry Andric return "Race on a library object"; 5285ffd83dbSDimitry Andric } else if (description == "swift-access-race") { 5295ffd83dbSDimitry Andric return "Swift access race"; 5305ffd83dbSDimitry Andric } 5315ffd83dbSDimitry Andric 5325ffd83dbSDimitry Andric // for unknown report codes just show the code 5335ffd83dbSDimitry Andric return description; 5345ffd83dbSDimitry Andric } 5355ffd83dbSDimitry Andric 5365ffd83dbSDimitry Andric static std::string Sprintf(const char *format, ...) { 5375ffd83dbSDimitry Andric StreamString s; 5385ffd83dbSDimitry Andric va_list args; 5395ffd83dbSDimitry Andric va_start(args, format); 5405ffd83dbSDimitry Andric s.PrintfVarArg(format, args); 5415ffd83dbSDimitry Andric va_end(args); 5425ffd83dbSDimitry Andric return std::string(s.GetString()); 5435ffd83dbSDimitry Andric } 5445ffd83dbSDimitry Andric 5455ffd83dbSDimitry Andric static std::string GetSymbolNameFromAddress(ProcessSP process_sp, addr_t addr) { 5465ffd83dbSDimitry Andric lldb_private::Address so_addr; 5475ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, 5485ffd83dbSDimitry Andric so_addr)) 5495ffd83dbSDimitry Andric return ""; 5505ffd83dbSDimitry Andric 5515ffd83dbSDimitry Andric lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol(); 5525ffd83dbSDimitry Andric if (!symbol) 5535ffd83dbSDimitry Andric return ""; 5545ffd83dbSDimitry Andric 5555ffd83dbSDimitry Andric std::string sym_name = symbol->GetName().GetCString(); 5565ffd83dbSDimitry Andric return sym_name; 5575ffd83dbSDimitry Andric } 5585ffd83dbSDimitry Andric 5595ffd83dbSDimitry Andric static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, 5605ffd83dbSDimitry Andric Declaration &decl) { 5615ffd83dbSDimitry Andric lldb_private::Address so_addr; 5625ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, 5635ffd83dbSDimitry Andric so_addr)) 5645ffd83dbSDimitry Andric return; 5655ffd83dbSDimitry Andric 5665ffd83dbSDimitry Andric lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol(); 5675ffd83dbSDimitry Andric if (!symbol) 5685ffd83dbSDimitry Andric return; 5695ffd83dbSDimitry Andric 5705ffd83dbSDimitry Andric ConstString sym_name = symbol->GetMangled().GetName(Mangled::ePreferMangled); 5715ffd83dbSDimitry Andric 5725ffd83dbSDimitry Andric ModuleSP module = symbol->CalculateSymbolContextModule(); 5735ffd83dbSDimitry Andric if (!module) 5745ffd83dbSDimitry Andric return; 5755ffd83dbSDimitry Andric 5765ffd83dbSDimitry Andric VariableList var_list; 5775ffd83dbSDimitry Andric module->FindGlobalVariables(sym_name, CompilerDeclContext(), 1U, var_list); 5785ffd83dbSDimitry Andric if (var_list.GetSize() < 1) 5795ffd83dbSDimitry Andric return; 5805ffd83dbSDimitry Andric 5815ffd83dbSDimitry Andric VariableSP var = var_list.GetVariableAtIndex(0); 5825ffd83dbSDimitry Andric decl = var->GetDeclaration(); 5835ffd83dbSDimitry Andric } 5845ffd83dbSDimitry Andric 5855ffd83dbSDimitry Andric addr_t InstrumentationRuntimeTSan::GetFirstNonInternalFramePc( 5865ffd83dbSDimitry Andric StructuredData::ObjectSP trace, bool skip_one_frame) { 5875ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 5885ffd83dbSDimitry Andric ModuleSP runtime_module_sp = GetRuntimeModuleSP(); 5895ffd83dbSDimitry Andric 5905ffd83dbSDimitry Andric StructuredData::Array *trace_array = trace->GetAsArray(); 5915ffd83dbSDimitry Andric for (size_t i = 0; i < trace_array->GetSize(); i++) { 5925ffd83dbSDimitry Andric if (skip_one_frame && i == 0) 5935ffd83dbSDimitry Andric continue; 5945ffd83dbSDimitry Andric 595*1db9f3b2SDimitry Andric auto maybe_addr = trace_array->GetItemAtIndexAsInteger<addr_t>(i); 596*1db9f3b2SDimitry Andric if (!maybe_addr) 5975ffd83dbSDimitry Andric continue; 598*1db9f3b2SDimitry Andric addr_t addr = *maybe_addr; 5995ffd83dbSDimitry Andric 6005ffd83dbSDimitry Andric lldb_private::Address so_addr; 6015ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( 6025ffd83dbSDimitry Andric addr, so_addr)) 6035ffd83dbSDimitry Andric continue; 6045ffd83dbSDimitry Andric 6055ffd83dbSDimitry Andric if (so_addr.GetModule() == runtime_module_sp) 6065ffd83dbSDimitry Andric continue; 6075ffd83dbSDimitry Andric 6085ffd83dbSDimitry Andric return addr; 6095ffd83dbSDimitry Andric } 6105ffd83dbSDimitry Andric 6115ffd83dbSDimitry Andric return 0; 6125ffd83dbSDimitry Andric } 6135ffd83dbSDimitry Andric 6145ffd83dbSDimitry Andric std::string 6155ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GenerateSummary(StructuredData::ObjectSP report) { 6165ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 6175ffd83dbSDimitry Andric 6185ffd83dbSDimitry Andric std::string summary = std::string(report->GetAsDictionary() 6195ffd83dbSDimitry Andric ->GetValueForKey("description") 6205ffd83dbSDimitry Andric ->GetAsString() 6215ffd83dbSDimitry Andric ->GetValue()); 6225ffd83dbSDimitry Andric bool skip_one_frame = 6235ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("issue_type")->GetStringValue() == 6245ffd83dbSDimitry Andric "external-race"; 6255ffd83dbSDimitry Andric 6265ffd83dbSDimitry Andric addr_t pc = 0; 6275ffd83dbSDimitry Andric if (report->GetAsDictionary() 6285ffd83dbSDimitry Andric ->GetValueForKey("mops") 6295ffd83dbSDimitry Andric ->GetAsArray() 6305ffd83dbSDimitry Andric ->GetSize() > 0) 6315ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6325ffd83dbSDimitry Andric ->GetValueForKey("mops") 6335ffd83dbSDimitry Andric ->GetAsArray() 6345ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6355ffd83dbSDimitry Andric ->GetAsDictionary() 6365ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6375ffd83dbSDimitry Andric skip_one_frame); 6385ffd83dbSDimitry Andric 6395ffd83dbSDimitry Andric if (report->GetAsDictionary() 6405ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6415ffd83dbSDimitry Andric ->GetAsArray() 6425ffd83dbSDimitry Andric ->GetSize() > 0) 6435ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6445ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6455ffd83dbSDimitry Andric ->GetAsArray() 6465ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6475ffd83dbSDimitry Andric ->GetAsDictionary() 6485ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6495ffd83dbSDimitry Andric skip_one_frame); 6505ffd83dbSDimitry Andric 6515ffd83dbSDimitry Andric if (pc != 0) { 6525ffd83dbSDimitry Andric summary = summary + " in " + GetSymbolNameFromAddress(process_sp, pc); 6535ffd83dbSDimitry Andric } 6545ffd83dbSDimitry Andric 6555ffd83dbSDimitry Andric if (report->GetAsDictionary() 6565ffd83dbSDimitry Andric ->GetValueForKey("locs") 6575ffd83dbSDimitry Andric ->GetAsArray() 6585ffd83dbSDimitry Andric ->GetSize() > 0) { 6595ffd83dbSDimitry Andric StructuredData::ObjectSP loc = report->GetAsDictionary() 6605ffd83dbSDimitry Andric ->GetValueForKey("locs") 6615ffd83dbSDimitry Andric ->GetAsArray() 6625ffd83dbSDimitry Andric ->GetItemAtIndex(0); 6635ffd83dbSDimitry Andric std::string object_type = std::string(loc->GetAsDictionary() 6645ffd83dbSDimitry Andric ->GetValueForKey("object_type") 6655ffd83dbSDimitry Andric ->GetAsString() 6665ffd83dbSDimitry Andric ->GetValue()); 6675ffd83dbSDimitry Andric if (!object_type.empty()) { 6685ffd83dbSDimitry Andric summary = "Race on " + object_type + " object"; 6695ffd83dbSDimitry Andric } 6705ffd83dbSDimitry Andric addr_t addr = loc->GetAsDictionary() 6715ffd83dbSDimitry Andric ->GetValueForKey("address") 67206c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 6735ffd83dbSDimitry Andric if (addr == 0) 6745ffd83dbSDimitry Andric addr = loc->GetAsDictionary() 6755ffd83dbSDimitry Andric ->GetValueForKey("start") 67606c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 6775ffd83dbSDimitry Andric 6785ffd83dbSDimitry Andric if (addr != 0) { 6795ffd83dbSDimitry Andric std::string global_name = GetSymbolNameFromAddress(process_sp, addr); 6805ffd83dbSDimitry Andric if (!global_name.empty()) { 6815ffd83dbSDimitry Andric summary = summary + " at " + global_name; 6825ffd83dbSDimitry Andric } else { 6835ffd83dbSDimitry Andric summary = summary + " at " + Sprintf("0x%llx", addr); 6845ffd83dbSDimitry Andric } 6855ffd83dbSDimitry Andric } else { 6865ffd83dbSDimitry Andric int fd = loc->GetAsDictionary() 6875ffd83dbSDimitry Andric ->GetValueForKey("file_descriptor") 68806c3fb27SDimitry Andric ->GetSignedIntegerValue(); 6895ffd83dbSDimitry Andric if (fd != 0) { 6905ffd83dbSDimitry Andric summary = summary + " on file descriptor " + Sprintf("%d", fd); 6915ffd83dbSDimitry Andric } 6925ffd83dbSDimitry Andric } 6935ffd83dbSDimitry Andric } 6945ffd83dbSDimitry Andric 6955ffd83dbSDimitry Andric return summary; 6965ffd83dbSDimitry Andric } 6975ffd83dbSDimitry Andric 6985ffd83dbSDimitry Andric addr_t InstrumentationRuntimeTSan::GetMainRacyAddress( 6995ffd83dbSDimitry Andric StructuredData::ObjectSP report) { 7005ffd83dbSDimitry Andric addr_t result = (addr_t)-1; 7015ffd83dbSDimitry Andric 7025ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach( 7035ffd83dbSDimitry Andric [&result](StructuredData::Object *o) -> bool { 70406c3fb27SDimitry Andric addr_t addr = o->GetObjectForDotSeparatedPath("address") 70506c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 7065ffd83dbSDimitry Andric if (addr < result) 7075ffd83dbSDimitry Andric result = addr; 7085ffd83dbSDimitry Andric return true; 7095ffd83dbSDimitry Andric }); 7105ffd83dbSDimitry Andric 7115ffd83dbSDimitry Andric return (result == (addr_t)-1) ? 0 : result; 7125ffd83dbSDimitry Andric } 7135ffd83dbSDimitry Andric 7145ffd83dbSDimitry Andric std::string InstrumentationRuntimeTSan::GetLocationDescription( 7155ffd83dbSDimitry Andric StructuredData::ObjectSP report, addr_t &global_addr, 7165ffd83dbSDimitry Andric std::string &global_name, std::string &filename, uint32_t &line) { 71704eeddc0SDimitry Andric std::string result; 7185ffd83dbSDimitry Andric 7195ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 7205ffd83dbSDimitry Andric 7215ffd83dbSDimitry Andric if (report->GetAsDictionary() 7225ffd83dbSDimitry Andric ->GetValueForKey("locs") 7235ffd83dbSDimitry Andric ->GetAsArray() 7245ffd83dbSDimitry Andric ->GetSize() > 0) { 7255ffd83dbSDimitry Andric StructuredData::ObjectSP loc = report->GetAsDictionary() 7265ffd83dbSDimitry Andric ->GetValueForKey("locs") 7275ffd83dbSDimitry Andric ->GetAsArray() 7285ffd83dbSDimitry Andric ->GetItemAtIndex(0); 7295ffd83dbSDimitry Andric std::string type = std::string( 7305ffd83dbSDimitry Andric loc->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); 7315ffd83dbSDimitry Andric if (type == "global") { 7325ffd83dbSDimitry Andric global_addr = loc->GetAsDictionary() 7335ffd83dbSDimitry Andric ->GetValueForKey("address") 73406c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 73506c3fb27SDimitry Andric 7365ffd83dbSDimitry Andric global_name = GetSymbolNameFromAddress(process_sp, global_addr); 7375ffd83dbSDimitry Andric if (!global_name.empty()) { 7385ffd83dbSDimitry Andric result = Sprintf("'%s' is a global variable (0x%llx)", 7395ffd83dbSDimitry Andric global_name.c_str(), global_addr); 7405ffd83dbSDimitry Andric } else { 7415ffd83dbSDimitry Andric result = Sprintf("0x%llx is a global variable", global_addr); 7425ffd83dbSDimitry Andric } 7435ffd83dbSDimitry Andric 7445ffd83dbSDimitry Andric Declaration decl; 7455ffd83dbSDimitry Andric GetSymbolDeclarationFromAddress(process_sp, global_addr, decl); 7465ffd83dbSDimitry Andric if (decl.GetFile()) { 7475ffd83dbSDimitry Andric filename = decl.GetFile().GetPath(); 7485ffd83dbSDimitry Andric line = decl.GetLine(); 7495ffd83dbSDimitry Andric } 7505ffd83dbSDimitry Andric } else if (type == "heap") { 7515ffd83dbSDimitry Andric addr_t addr = loc->GetAsDictionary() 7525ffd83dbSDimitry Andric ->GetValueForKey("start") 75306c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 75406c3fb27SDimitry Andric 75506c3fb27SDimitry Andric size_t size = loc->GetAsDictionary() 7565ffd83dbSDimitry Andric ->GetValueForKey("size") 75706c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 75806c3fb27SDimitry Andric 7595ffd83dbSDimitry Andric std::string object_type = std::string(loc->GetAsDictionary() 7605ffd83dbSDimitry Andric ->GetValueForKey("object_type") 7615ffd83dbSDimitry Andric ->GetAsString() 7625ffd83dbSDimitry Andric ->GetValue()); 7635ffd83dbSDimitry Andric if (!object_type.empty()) { 7645ffd83dbSDimitry Andric result = Sprintf("Location is a %ld-byte %s object at 0x%llx", size, 7655ffd83dbSDimitry Andric object_type.c_str(), addr); 7665ffd83dbSDimitry Andric } else { 7675ffd83dbSDimitry Andric result = 7685ffd83dbSDimitry Andric Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); 7695ffd83dbSDimitry Andric } 7705ffd83dbSDimitry Andric } else if (type == "stack") { 77106c3fb27SDimitry Andric tid_t tid = loc->GetAsDictionary() 7725ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 77306c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 77406c3fb27SDimitry Andric 7755ffd83dbSDimitry Andric result = Sprintf("Location is stack of thread %d", tid); 7765ffd83dbSDimitry Andric } else if (type == "tls") { 77706c3fb27SDimitry Andric tid_t tid = loc->GetAsDictionary() 7785ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 77906c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 78006c3fb27SDimitry Andric 7815ffd83dbSDimitry Andric result = Sprintf("Location is TLS of thread %d", tid); 7825ffd83dbSDimitry Andric } else if (type == "fd") { 7835ffd83dbSDimitry Andric int fd = loc->GetAsDictionary() 7845ffd83dbSDimitry Andric ->GetValueForKey("file_descriptor") 78506c3fb27SDimitry Andric ->GetSignedIntegerValue(); 78606c3fb27SDimitry Andric 7875ffd83dbSDimitry Andric result = Sprintf("Location is file descriptor %d", fd); 7885ffd83dbSDimitry Andric } 7895ffd83dbSDimitry Andric } 7905ffd83dbSDimitry Andric 7915ffd83dbSDimitry Andric return result; 7925ffd83dbSDimitry Andric } 7935ffd83dbSDimitry Andric 7945ffd83dbSDimitry Andric bool InstrumentationRuntimeTSan::NotifyBreakpointHit( 7955ffd83dbSDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 7965ffd83dbSDimitry Andric user_id_t break_loc_id) { 7975ffd83dbSDimitry Andric assert(baton && "null baton"); 7985ffd83dbSDimitry Andric if (!baton) 7995ffd83dbSDimitry Andric return false; 8005ffd83dbSDimitry Andric 8015ffd83dbSDimitry Andric InstrumentationRuntimeTSan *const instance = 8025ffd83dbSDimitry Andric static_cast<InstrumentationRuntimeTSan *>(baton); 8035ffd83dbSDimitry Andric 8045ffd83dbSDimitry Andric ProcessSP process_sp = instance->GetProcessSP(); 8055ffd83dbSDimitry Andric 8065ffd83dbSDimitry Andric if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) 8075ffd83dbSDimitry Andric return false; 8085ffd83dbSDimitry Andric 8095ffd83dbSDimitry Andric StructuredData::ObjectSP report = 8105ffd83dbSDimitry Andric instance->RetrieveReportData(context->exe_ctx_ref); 811e8d8bef9SDimitry Andric std::string stop_reason_description = 812e8d8bef9SDimitry Andric "unknown thread sanitizer fault (unable to extract thread sanitizer " 813e8d8bef9SDimitry Andric "report)"; 8145ffd83dbSDimitry Andric if (report) { 8155ffd83dbSDimitry Andric std::string issue_description = instance->FormatDescription(report); 8165ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("description", issue_description); 8175ffd83dbSDimitry Andric stop_reason_description = issue_description + " detected"; 8185ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("stop_description", 8195ffd83dbSDimitry Andric stop_reason_description); 8205ffd83dbSDimitry Andric std::string summary = instance->GenerateSummary(report); 8215ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("summary", summary); 8225ffd83dbSDimitry Andric addr_t main_address = instance->GetMainRacyAddress(report); 8235ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("memory_address", main_address); 8245ffd83dbSDimitry Andric 8255ffd83dbSDimitry Andric addr_t global_addr = 0; 82604eeddc0SDimitry Andric std::string global_name; 82704eeddc0SDimitry Andric std::string location_filename; 8285ffd83dbSDimitry Andric uint32_t location_line = 0; 8295ffd83dbSDimitry Andric std::string location_description = instance->GetLocationDescription( 8305ffd83dbSDimitry Andric report, global_addr, global_name, location_filename, location_line); 8315ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("location_description", 8325ffd83dbSDimitry Andric location_description); 8335ffd83dbSDimitry Andric if (global_addr != 0) { 8345ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("global_address", global_addr); 8355ffd83dbSDimitry Andric } 8365ffd83dbSDimitry Andric if (!global_name.empty()) { 8375ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("global_name", global_name); 8385ffd83dbSDimitry Andric } 8395ffd83dbSDimitry Andric if (location_filename != "") { 8405ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("location_filename", 8415ffd83dbSDimitry Andric location_filename); 8425ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("location_line", location_line); 8435ffd83dbSDimitry Andric } 8445ffd83dbSDimitry Andric 8455ffd83dbSDimitry Andric bool all_addresses_are_same = true; 8465ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach( 8475ffd83dbSDimitry Andric [&all_addresses_are_same, 8485ffd83dbSDimitry Andric main_address](StructuredData::Object *o) -> bool { 84906c3fb27SDimitry Andric addr_t addr = o->GetObjectForDotSeparatedPath("address") 85006c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 8515ffd83dbSDimitry Andric if (main_address != addr) 8525ffd83dbSDimitry Andric all_addresses_are_same = false; 8535ffd83dbSDimitry Andric return true; 8545ffd83dbSDimitry Andric }); 8555ffd83dbSDimitry Andric report->GetAsDictionary()->AddBooleanItem("all_addresses_are_same", 8565ffd83dbSDimitry Andric all_addresses_are_same); 8575ffd83dbSDimitry Andric } 8585ffd83dbSDimitry Andric 8595ffd83dbSDimitry Andric // Make sure this is the right process 8605ffd83dbSDimitry Andric if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) { 8615ffd83dbSDimitry Andric ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); 8625ffd83dbSDimitry Andric if (thread_sp) 8635ffd83dbSDimitry Andric thread_sp->SetStopInfo( 8645ffd83dbSDimitry Andric InstrumentationRuntimeStopInfo:: 8655ffd83dbSDimitry Andric CreateStopReasonWithInstrumentationData( 8665ffd83dbSDimitry Andric *thread_sp, stop_reason_description, report)); 8675ffd83dbSDimitry Andric 8685ffd83dbSDimitry Andric StreamFile &s = process_sp->GetTarget().GetDebugger().GetOutputStream(); 8695ffd83dbSDimitry Andric s.Printf("ThreadSanitizer report breakpoint hit. Use 'thread " 8705ffd83dbSDimitry Andric "info -s' to get extended information about the " 8715ffd83dbSDimitry Andric "report.\n"); 8725ffd83dbSDimitry Andric 8735ffd83dbSDimitry Andric return true; // Return true to stop the target 8745ffd83dbSDimitry Andric } else 8755ffd83dbSDimitry Andric return false; // Let target run 8765ffd83dbSDimitry Andric } 8775ffd83dbSDimitry Andric 8785ffd83dbSDimitry Andric const RegularExpression & 8795ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GetPatternForRuntimeLibrary() { 8805ffd83dbSDimitry Andric static RegularExpression regex(llvm::StringRef("libclang_rt.tsan_")); 8815ffd83dbSDimitry Andric return regex; 8825ffd83dbSDimitry Andric } 8835ffd83dbSDimitry Andric 8845ffd83dbSDimitry Andric bool InstrumentationRuntimeTSan::CheckIfRuntimeIsValid( 8855ffd83dbSDimitry Andric const lldb::ModuleSP module_sp) { 8865ffd83dbSDimitry Andric static ConstString g_tsan_get_current_report("__tsan_get_current_report"); 8875ffd83dbSDimitry Andric const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( 8885ffd83dbSDimitry Andric g_tsan_get_current_report, lldb::eSymbolTypeAny); 8895ffd83dbSDimitry Andric return symbol != nullptr; 8905ffd83dbSDimitry Andric } 8915ffd83dbSDimitry Andric 8925ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Activate() { 8935ffd83dbSDimitry Andric if (IsActive()) 8945ffd83dbSDimitry Andric return; 8955ffd83dbSDimitry Andric 8965ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 8975ffd83dbSDimitry Andric if (!process_sp) 8985ffd83dbSDimitry Andric return; 8995ffd83dbSDimitry Andric 9005ffd83dbSDimitry Andric ConstString symbol_name("__tsan_on_report"); 9015ffd83dbSDimitry Andric const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType( 9025ffd83dbSDimitry Andric symbol_name, eSymbolTypeCode); 9035ffd83dbSDimitry Andric 9045ffd83dbSDimitry Andric if (symbol == nullptr) 9055ffd83dbSDimitry Andric return; 9065ffd83dbSDimitry Andric 9075ffd83dbSDimitry Andric if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) 9085ffd83dbSDimitry Andric return; 9095ffd83dbSDimitry Andric 9105ffd83dbSDimitry Andric Target &target = process_sp->GetTarget(); 9115ffd83dbSDimitry Andric addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); 9125ffd83dbSDimitry Andric 9135ffd83dbSDimitry Andric if (symbol_address == LLDB_INVALID_ADDRESS) 9145ffd83dbSDimitry Andric return; 9155ffd83dbSDimitry Andric 916bdd1243dSDimitry Andric const bool internal = true; 917bdd1243dSDimitry Andric const bool hardware = false; 918bdd1243dSDimitry Andric const bool sync = false; 9195ffd83dbSDimitry Andric Breakpoint *breakpoint = 9205ffd83dbSDimitry Andric process_sp->GetTarget() 9215ffd83dbSDimitry Andric .CreateBreakpoint(symbol_address, internal, hardware) 9225ffd83dbSDimitry Andric .get(); 9235ffd83dbSDimitry Andric breakpoint->SetCallback(InstrumentationRuntimeTSan::NotifyBreakpointHit, this, 924bdd1243dSDimitry Andric sync); 9255ffd83dbSDimitry Andric breakpoint->SetBreakpointKind("thread-sanitizer-report"); 9265ffd83dbSDimitry Andric SetBreakpointID(breakpoint->GetID()); 9275ffd83dbSDimitry Andric 9285ffd83dbSDimitry Andric SetActive(true); 9295ffd83dbSDimitry Andric } 9305ffd83dbSDimitry Andric 9315ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Deactivate() { 9325ffd83dbSDimitry Andric if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 9335ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 9345ffd83dbSDimitry Andric if (process_sp) { 9355ffd83dbSDimitry Andric process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID()); 9365ffd83dbSDimitry Andric SetBreakpointID(LLDB_INVALID_BREAK_ID); 9375ffd83dbSDimitry Andric } 9385ffd83dbSDimitry Andric } 9395ffd83dbSDimitry Andric SetActive(false); 9405ffd83dbSDimitry Andric } 9415ffd83dbSDimitry Andric static std::string GenerateThreadName(const std::string &path, 9425ffd83dbSDimitry Andric StructuredData::Object *o, 9435ffd83dbSDimitry Andric StructuredData::ObjectSP main_info) { 9445ffd83dbSDimitry Andric std::string result = "additional information"; 9455ffd83dbSDimitry Andric 9465ffd83dbSDimitry Andric if (path == "mops") { 94706c3fb27SDimitry Andric size_t size = 94806c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); 94906c3fb27SDimitry Andric tid_t thread_id = 95006c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 9515ffd83dbSDimitry Andric bool is_write = 9525ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); 9535ffd83dbSDimitry Andric bool is_atomic = 9545ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_atomic")->GetBooleanValue(); 95506c3fb27SDimitry Andric addr_t addr = 95606c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("address")->GetUnsignedIntegerValue(); 9575ffd83dbSDimitry Andric 9585ffd83dbSDimitry Andric std::string addr_string = Sprintf(" at 0x%llx", addr); 9595ffd83dbSDimitry Andric 9605ffd83dbSDimitry Andric if (main_info->GetObjectForDotSeparatedPath("all_addresses_are_same") 9615ffd83dbSDimitry Andric ->GetBooleanValue()) { 9625ffd83dbSDimitry Andric addr_string = ""; 9635ffd83dbSDimitry Andric } 9645ffd83dbSDimitry Andric 9655ffd83dbSDimitry Andric if (main_info->GetObjectForDotSeparatedPath("issue_type") 9665ffd83dbSDimitry Andric ->GetStringValue() == "external-race") { 9675ffd83dbSDimitry Andric result = Sprintf("%s access by thread %d", 9685ffd83dbSDimitry Andric is_write ? "mutating" : "read-only", thread_id); 9695ffd83dbSDimitry Andric } else if (main_info->GetObjectForDotSeparatedPath("issue_type") 9705ffd83dbSDimitry Andric ->GetStringValue() == "swift-access-race") { 9715ffd83dbSDimitry Andric result = Sprintf("modifying access by thread %d", thread_id); 9725ffd83dbSDimitry Andric } else { 97306c3fb27SDimitry Andric result = Sprintf("%s%s of size %zu%s by thread %" PRIu64, 9745ffd83dbSDimitry Andric is_atomic ? "atomic " : "", is_write ? "write" : "read", 9755ffd83dbSDimitry Andric size, addr_string.c_str(), thread_id); 9765ffd83dbSDimitry Andric } 9775ffd83dbSDimitry Andric } 9785ffd83dbSDimitry Andric 9795ffd83dbSDimitry Andric if (path == "threads") { 98006c3fb27SDimitry Andric tid_t thread_id = 98106c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 98206c3fb27SDimitry Andric result = Sprintf("Thread %zu created", thread_id); 9835ffd83dbSDimitry Andric } 9845ffd83dbSDimitry Andric 9855ffd83dbSDimitry Andric if (path == "locs") { 9865ffd83dbSDimitry Andric std::string type = std::string( 9875ffd83dbSDimitry Andric o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); 98806c3fb27SDimitry Andric tid_t thread_id = 98906c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 99006c3fb27SDimitry Andric int fd = o->GetObjectForDotSeparatedPath("file_descriptor") 99106c3fb27SDimitry Andric ->GetSignedIntegerValue(); 9925ffd83dbSDimitry Andric if (type == "heap") { 99306c3fb27SDimitry Andric result = Sprintf("Heap block allocated by thread %" PRIu64, thread_id); 9945ffd83dbSDimitry Andric } else if (type == "fd") { 99506c3fb27SDimitry Andric result = Sprintf("File descriptor %d created by thread %" PRIu64, fd, 99606c3fb27SDimitry Andric thread_id); 9975ffd83dbSDimitry Andric } 9985ffd83dbSDimitry Andric } 9995ffd83dbSDimitry Andric 10005ffd83dbSDimitry Andric if (path == "mutexes") { 10015ffd83dbSDimitry Andric int mutex_id = 100206c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("mutex_id")->GetSignedIntegerValue(); 10035ffd83dbSDimitry Andric 10045ffd83dbSDimitry Andric result = Sprintf("Mutex M%d created", mutex_id); 10055ffd83dbSDimitry Andric } 10065ffd83dbSDimitry Andric 10075ffd83dbSDimitry Andric if (path == "stacks") { 100806c3fb27SDimitry Andric tid_t thread_id = 100906c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 101006c3fb27SDimitry Andric result = Sprintf("Thread %" PRIu64, thread_id); 10115ffd83dbSDimitry Andric } 10125ffd83dbSDimitry Andric 10135ffd83dbSDimitry Andric result[0] = toupper(result[0]); 10145ffd83dbSDimitry Andric 10155ffd83dbSDimitry Andric return result; 10165ffd83dbSDimitry Andric } 10175ffd83dbSDimitry Andric 10185ffd83dbSDimitry Andric static void AddThreadsForPath(const std::string &path, 10195ffd83dbSDimitry Andric ThreadCollectionSP threads, ProcessSP process_sp, 10205ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 10215ffd83dbSDimitry Andric info->GetObjectForDotSeparatedPath(path)->GetAsArray()->ForEach( 10225ffd83dbSDimitry Andric [process_sp, threads, path, info](StructuredData::Object *o) -> bool { 10235ffd83dbSDimitry Andric std::vector<lldb::addr_t> pcs; 10245ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("trace")->GetAsArray()->ForEach( 10255ffd83dbSDimitry Andric [&pcs](StructuredData::Object *pc) -> bool { 102606c3fb27SDimitry Andric pcs.push_back(pc->GetUnsignedIntegerValue()); 10275ffd83dbSDimitry Andric return true; 10285ffd83dbSDimitry Andric }); 10295ffd83dbSDimitry Andric 10305ffd83dbSDimitry Andric if (pcs.size() == 0) 10315ffd83dbSDimitry Andric return true; 10325ffd83dbSDimitry Andric 10335ffd83dbSDimitry Andric StructuredData::ObjectSP thread_id_obj = 10345ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_os_id"); 103506c3fb27SDimitry Andric tid_t tid = 103606c3fb27SDimitry Andric thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; 10375ffd83dbSDimitry Andric 1038bdd1243dSDimitry Andric ThreadSP new_thread_sp = 1039bdd1243dSDimitry Andric std::make_shared<HistoryThread>(*process_sp, tid, pcs); 10405ffd83dbSDimitry Andric new_thread_sp->SetName(GenerateThreadName(path, o, info).c_str()); 10415ffd83dbSDimitry Andric 10425ffd83dbSDimitry Andric // Save this in the Process' ExtendedThreadList so a strong pointer 10435ffd83dbSDimitry Andric // retains the object 10445ffd83dbSDimitry Andric process_sp->GetExtendedThreadList().AddThread(new_thread_sp); 10455ffd83dbSDimitry Andric threads->AddThread(new_thread_sp); 10465ffd83dbSDimitry Andric 10475ffd83dbSDimitry Andric return true; 10485ffd83dbSDimitry Andric }); 10495ffd83dbSDimitry Andric } 10505ffd83dbSDimitry Andric 10515ffd83dbSDimitry Andric lldb::ThreadCollectionSP 10525ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GetBacktracesFromExtendedStopInfo( 10535ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 1054bdd1243dSDimitry Andric 1055bdd1243dSDimitry Andric ThreadCollectionSP threads = std::make_shared<ThreadCollection>(); 10565ffd83dbSDimitry Andric 10575ffd83dbSDimitry Andric if (info->GetObjectForDotSeparatedPath("instrumentation_class") 10585ffd83dbSDimitry Andric ->GetStringValue() != "ThreadSanitizer") 10595ffd83dbSDimitry Andric return threads; 10605ffd83dbSDimitry Andric 10615ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 10625ffd83dbSDimitry Andric 10635ffd83dbSDimitry Andric AddThreadsForPath("stacks", threads, process_sp, info); 10645ffd83dbSDimitry Andric AddThreadsForPath("mops", threads, process_sp, info); 10655ffd83dbSDimitry Andric AddThreadsForPath("locs", threads, process_sp, info); 10665ffd83dbSDimitry Andric AddThreadsForPath("mutexes", threads, process_sp, info); 10675ffd83dbSDimitry Andric AddThreadsForPath("threads", threads, process_sp, info); 10685ffd83dbSDimitry Andric 10695ffd83dbSDimitry Andric return threads; 10705ffd83dbSDimitry Andric } 1071