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" 30*0fca6ea1SDimitry Andric #include "lldb/Utility/LLDBLog.h" 31*0fca6ea1SDimitry Andric #include "lldb/Utility/Log.h" 325ffd83dbSDimitry Andric #include "lldb/Utility/RegularExpression.h" 335ffd83dbSDimitry Andric #include "lldb/Utility/Stream.h" 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric #include <memory> 365ffd83dbSDimitry Andric 375ffd83dbSDimitry Andric using namespace lldb; 385ffd83dbSDimitry Andric using namespace lldb_private; 395ffd83dbSDimitry Andric 405ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(InstrumentationRuntimeTSan) 415ffd83dbSDimitry Andric 425ffd83dbSDimitry Andric lldb::InstrumentationRuntimeSP 435ffd83dbSDimitry Andric InstrumentationRuntimeTSan::CreateInstance(const lldb::ProcessSP &process_sp) { 445ffd83dbSDimitry Andric return InstrumentationRuntimeSP(new InstrumentationRuntimeTSan(process_sp)); 455ffd83dbSDimitry Andric } 465ffd83dbSDimitry Andric 475ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Initialize() { 485ffd83dbSDimitry Andric PluginManager::RegisterPlugin( 495ffd83dbSDimitry Andric GetPluginNameStatic(), "ThreadSanitizer instrumentation runtime plugin.", 505ffd83dbSDimitry Andric CreateInstance, GetTypeStatic); 515ffd83dbSDimitry Andric } 525ffd83dbSDimitry Andric 535ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Terminate() { 545ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 555ffd83dbSDimitry Andric } 565ffd83dbSDimitry Andric 575ffd83dbSDimitry Andric lldb::InstrumentationRuntimeType InstrumentationRuntimeTSan::GetTypeStatic() { 585ffd83dbSDimitry Andric return eInstrumentationRuntimeTypeThreadSanitizer; 595ffd83dbSDimitry Andric } 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric InstrumentationRuntimeTSan::~InstrumentationRuntimeTSan() { Deactivate(); } 625ffd83dbSDimitry Andric 635ffd83dbSDimitry Andric const char *thread_sanitizer_retrieve_report_data_prefix = R"( 645ffd83dbSDimitry Andric extern "C" 655ffd83dbSDimitry Andric { 665ffd83dbSDimitry Andric void *__tsan_get_current_report(); 675ffd83dbSDimitry Andric int __tsan_get_report_data(void *report, const char **description, int *count, 685ffd83dbSDimitry Andric int *stack_count, int *mop_count, int *loc_count, 695ffd83dbSDimitry Andric int *mutex_count, int *thread_count, 705ffd83dbSDimitry Andric int *unique_tid_count, void **sleep_trace, 715ffd83dbSDimitry Andric unsigned long trace_size); 725ffd83dbSDimitry Andric int __tsan_get_report_stack(void *report, unsigned long idx, void **trace, 735ffd83dbSDimitry Andric unsigned long trace_size); 745ffd83dbSDimitry Andric int __tsan_get_report_mop(void *report, unsigned long idx, int *tid, void **addr, 755ffd83dbSDimitry Andric int *size, int *write, int *atomic, void **trace, 765ffd83dbSDimitry Andric unsigned long trace_size); 775ffd83dbSDimitry Andric int __tsan_get_report_loc(void *report, unsigned long idx, const char **type, 785ffd83dbSDimitry Andric void **addr, unsigned long *start, unsigned long *size, int *tid, 795ffd83dbSDimitry Andric int *fd, int *suppressable, void **trace, 805ffd83dbSDimitry Andric unsigned long trace_size); 815ffd83dbSDimitry Andric int __tsan_get_report_mutex(void *report, unsigned long idx, unsigned long *mutex_id, void **addr, 825ffd83dbSDimitry Andric int *destroyed, void **trace, unsigned long trace_size); 835ffd83dbSDimitry Andric int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *os_id, 845ffd83dbSDimitry Andric int *running, const char **name, int *parent_tid, 855ffd83dbSDimitry Andric void **trace, unsigned long trace_size); 865ffd83dbSDimitry Andric int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid); 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric // TODO: dlsym won't work on Windows. 895ffd83dbSDimitry Andric void *dlsym(void* handle, const char* symbol); 905ffd83dbSDimitry Andric int (*ptr__tsan_get_report_loc_object_type)(void *report, unsigned long idx, const char **object_type); 915ffd83dbSDimitry Andric } 9206c3fb27SDimitry Andric )"; 9306c3fb27SDimitry Andric 9406c3fb27SDimitry Andric const char *thread_sanitizer_retrieve_report_data_command = R"( 955ffd83dbSDimitry Andric 965ffd83dbSDimitry Andric const int REPORT_TRACE_SIZE = 128; 975ffd83dbSDimitry Andric const int REPORT_ARRAY_SIZE = 4; 985ffd83dbSDimitry Andric 9906c3fb27SDimitry Andric struct { 1005ffd83dbSDimitry Andric void *report; 1015ffd83dbSDimitry Andric const char *description; 1025ffd83dbSDimitry Andric int report_count; 1035ffd83dbSDimitry Andric 1045ffd83dbSDimitry Andric void *sleep_trace[REPORT_TRACE_SIZE]; 1055ffd83dbSDimitry Andric 1065ffd83dbSDimitry Andric int stack_count; 1075ffd83dbSDimitry Andric struct { 1085ffd83dbSDimitry Andric int idx; 1095ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1105ffd83dbSDimitry Andric } stacks[REPORT_ARRAY_SIZE]; 1115ffd83dbSDimitry Andric 1125ffd83dbSDimitry Andric int mop_count; 1135ffd83dbSDimitry Andric struct { 1145ffd83dbSDimitry Andric int idx; 1155ffd83dbSDimitry Andric int tid; 1165ffd83dbSDimitry Andric int size; 1175ffd83dbSDimitry Andric int write; 1185ffd83dbSDimitry Andric int atomic; 1195ffd83dbSDimitry Andric void *addr; 1205ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1215ffd83dbSDimitry Andric } mops[REPORT_ARRAY_SIZE]; 1225ffd83dbSDimitry Andric 1235ffd83dbSDimitry Andric int loc_count; 1245ffd83dbSDimitry Andric struct { 1255ffd83dbSDimitry Andric int idx; 1265ffd83dbSDimitry Andric const char *type; 1275ffd83dbSDimitry Andric void *addr; 1285ffd83dbSDimitry Andric unsigned long start; 1295ffd83dbSDimitry Andric unsigned long size; 1305ffd83dbSDimitry Andric int tid; 1315ffd83dbSDimitry Andric int fd; 1325ffd83dbSDimitry Andric int suppressable; 1335ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1345ffd83dbSDimitry Andric const char *object_type; 1355ffd83dbSDimitry Andric } locs[REPORT_ARRAY_SIZE]; 1365ffd83dbSDimitry Andric 1375ffd83dbSDimitry Andric int mutex_count; 1385ffd83dbSDimitry Andric struct { 1395ffd83dbSDimitry Andric int idx; 1405ffd83dbSDimitry Andric unsigned long mutex_id; 1415ffd83dbSDimitry Andric void *addr; 1425ffd83dbSDimitry Andric int destroyed; 1435ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1445ffd83dbSDimitry Andric } mutexes[REPORT_ARRAY_SIZE]; 1455ffd83dbSDimitry Andric 1465ffd83dbSDimitry Andric int thread_count; 1475ffd83dbSDimitry Andric struct { 1485ffd83dbSDimitry Andric int idx; 1495ffd83dbSDimitry Andric int tid; 1505ffd83dbSDimitry Andric unsigned long os_id; 1515ffd83dbSDimitry Andric int running; 1525ffd83dbSDimitry Andric const char *name; 1535ffd83dbSDimitry Andric int parent_tid; 1545ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1555ffd83dbSDimitry Andric } threads[REPORT_ARRAY_SIZE]; 1565ffd83dbSDimitry Andric 1575ffd83dbSDimitry Andric int unique_tid_count; 1585ffd83dbSDimitry Andric struct { 1595ffd83dbSDimitry Andric int idx; 1605ffd83dbSDimitry Andric int tid; 1615ffd83dbSDimitry Andric } unique_tids[REPORT_ARRAY_SIZE]; 16206c3fb27SDimitry Andric } t = {0}; 1635ffd83dbSDimitry Andric 1645ffd83dbSDimitry 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"); 1655ffd83dbSDimitry Andric 1665ffd83dbSDimitry Andric t.report = __tsan_get_current_report(); 1675ffd83dbSDimitry 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); 1685ffd83dbSDimitry Andric 1695ffd83dbSDimitry Andric if (t.stack_count > REPORT_ARRAY_SIZE) t.stack_count = REPORT_ARRAY_SIZE; 1705ffd83dbSDimitry Andric for (int i = 0; i < t.stack_count; i++) { 1715ffd83dbSDimitry Andric t.stacks[i].idx = i; 1725ffd83dbSDimitry Andric __tsan_get_report_stack(t.report, i, t.stacks[i].trace, REPORT_TRACE_SIZE); 1735ffd83dbSDimitry Andric } 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric if (t.mop_count > REPORT_ARRAY_SIZE) t.mop_count = REPORT_ARRAY_SIZE; 1765ffd83dbSDimitry Andric for (int i = 0; i < t.mop_count; i++) { 1775ffd83dbSDimitry Andric t.mops[i].idx = i; 1785ffd83dbSDimitry 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); 1795ffd83dbSDimitry Andric } 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE; 1825ffd83dbSDimitry Andric for (int i = 0; i < t.loc_count; i++) { 1835ffd83dbSDimitry Andric t.locs[i].idx = i; 1845ffd83dbSDimitry 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); 1855ffd83dbSDimitry Andric if (ptr__tsan_get_report_loc_object_type) 1865ffd83dbSDimitry Andric ptr__tsan_get_report_loc_object_type(t.report, i, &t.locs[i].object_type); 1875ffd83dbSDimitry Andric } 1885ffd83dbSDimitry Andric 1895ffd83dbSDimitry Andric if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE; 1905ffd83dbSDimitry Andric for (int i = 0; i < t.mutex_count; i++) { 1915ffd83dbSDimitry Andric t.mutexes[i].idx = i; 1925ffd83dbSDimitry 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); 1935ffd83dbSDimitry Andric } 1945ffd83dbSDimitry Andric 1955ffd83dbSDimitry Andric if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE; 1965ffd83dbSDimitry Andric for (int i = 0; i < t.thread_count; i++) { 1975ffd83dbSDimitry Andric t.threads[i].idx = i; 1985ffd83dbSDimitry 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); 1995ffd83dbSDimitry Andric } 2005ffd83dbSDimitry Andric 2015ffd83dbSDimitry Andric if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE; 2025ffd83dbSDimitry Andric for (int i = 0; i < t.unique_tid_count; i++) { 2035ffd83dbSDimitry Andric t.unique_tids[i].idx = i; 2045ffd83dbSDimitry Andric __tsan_get_report_unique_tid(t.report, i, &t.unique_tids[i].tid); 2055ffd83dbSDimitry Andric } 2065ffd83dbSDimitry Andric 2075ffd83dbSDimitry Andric t; 2085ffd83dbSDimitry Andric )"; 2095ffd83dbSDimitry Andric 210bdd1243dSDimitry Andric static StructuredData::ArraySP 2115ffd83dbSDimitry Andric CreateStackTrace(ValueObjectSP o, 2125ffd83dbSDimitry Andric const std::string &trace_item_name = ".trace") { 213bdd1243dSDimitry Andric auto trace_sp = std::make_shared<StructuredData::Array>(); 2145ffd83dbSDimitry Andric ValueObjectSP trace_value_object = 2155ffd83dbSDimitry Andric o->GetValueForExpressionPath(trace_item_name.c_str()); 216*0fca6ea1SDimitry Andric size_t count = trace_value_object->GetNumChildrenIgnoringErrors(); 2175ffd83dbSDimitry Andric for (size_t j = 0; j < count; j++) { 2185ffd83dbSDimitry Andric addr_t trace_addr = 21906c3fb27SDimitry Andric trace_value_object->GetChildAtIndex(j)->GetValueAsUnsigned(0); 2205ffd83dbSDimitry Andric if (trace_addr == 0) 2215ffd83dbSDimitry Andric break; 22206c3fb27SDimitry Andric trace_sp->AddIntegerItem(trace_addr); 2235ffd83dbSDimitry Andric } 224bdd1243dSDimitry Andric return trace_sp; 2255ffd83dbSDimitry Andric } 2265ffd83dbSDimitry Andric 227bdd1243dSDimitry Andric static StructuredData::ArraySP ConvertToStructuredArray( 2285ffd83dbSDimitry Andric ValueObjectSP return_value_sp, const std::string &items_name, 2295ffd83dbSDimitry Andric const std::string &count_name, 230bdd1243dSDimitry Andric std::function<void(const ValueObjectSP &o, 231bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict)> const 2325ffd83dbSDimitry Andric &callback) { 233bdd1243dSDimitry Andric auto array_sp = std::make_shared<StructuredData::Array>(); 2345ffd83dbSDimitry Andric unsigned int count = 2355ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(count_name.c_str()) 2365ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2375ffd83dbSDimitry Andric ValueObjectSP objects = 2385ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(items_name.c_str()); 2395ffd83dbSDimitry Andric for (unsigned int i = 0; i < count; i++) { 24006c3fb27SDimitry Andric ValueObjectSP o = objects->GetChildAtIndex(i); 241bdd1243dSDimitry Andric auto dict_sp = std::make_shared<StructuredData::Dictionary>(); 2425ffd83dbSDimitry Andric 243bdd1243dSDimitry Andric callback(o, dict_sp); 2445ffd83dbSDimitry Andric 245bdd1243dSDimitry Andric array_sp->AddItem(dict_sp); 2465ffd83dbSDimitry Andric } 247bdd1243dSDimitry Andric return array_sp; 2485ffd83dbSDimitry Andric } 2495ffd83dbSDimitry Andric 2505ffd83dbSDimitry Andric static std::string RetrieveString(ValueObjectSP return_value_sp, 2515ffd83dbSDimitry Andric ProcessSP process_sp, 2525ffd83dbSDimitry Andric const std::string &expression_path) { 2535ffd83dbSDimitry Andric addr_t ptr = 2545ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(expression_path.c_str()) 2555ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2565ffd83dbSDimitry Andric std::string str; 2575ffd83dbSDimitry Andric Status error; 2585ffd83dbSDimitry Andric process_sp->ReadCStringFromMemory(ptr, str, error); 2595ffd83dbSDimitry Andric return str; 2605ffd83dbSDimitry Andric } 2615ffd83dbSDimitry Andric 2625ffd83dbSDimitry Andric static void 2635ffd83dbSDimitry Andric GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, 2645ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2655ffd83dbSDimitry Andric ConvertToStructuredArray( 2665ffd83dbSDimitry Andric data, ".threads", ".thread_count", 267bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 268bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 2695ffd83dbSDimitry Andric uint64_t thread_id = 2705ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0); 2715ffd83dbSDimitry Andric uint64_t thread_os_id = 2725ffd83dbSDimitry Andric o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0); 2735ffd83dbSDimitry Andric user_id_t lldb_user_id = 0; 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric bool can_update = true; 2765ffd83dbSDimitry Andric ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID( 2775ffd83dbSDimitry Andric thread_os_id, can_update); 2785ffd83dbSDimitry Andric if (lldb_thread) { 2795ffd83dbSDimitry Andric lldb_user_id = lldb_thread->GetIndexID(); 2805ffd83dbSDimitry Andric } else { 2815ffd83dbSDimitry Andric // This isn't a live thread anymore. Ask process to assign a new 2825ffd83dbSDimitry Andric // Index ID (or return an old one if we've already seen this 2835ffd83dbSDimitry Andric // thread_os_id). It will also make sure that no new threads are 2845ffd83dbSDimitry Andric // assigned this Index ID. 2855ffd83dbSDimitry Andric lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id); 2865ffd83dbSDimitry Andric } 2875ffd83dbSDimitry Andric 2885ffd83dbSDimitry Andric thread_id_map[thread_id] = lldb_user_id; 2895ffd83dbSDimitry Andric }); 2905ffd83dbSDimitry Andric } 2915ffd83dbSDimitry Andric 2925ffd83dbSDimitry Andric static user_id_t Renumber(uint64_t id, 2935ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2945ffd83dbSDimitry Andric auto IT = thread_id_map.find(id); 2955ffd83dbSDimitry Andric if (IT == thread_id_map.end()) 2965ffd83dbSDimitry Andric return 0; 2975ffd83dbSDimitry Andric 2985ffd83dbSDimitry Andric return IT->second; 2995ffd83dbSDimitry Andric } 3005ffd83dbSDimitry Andric 3015ffd83dbSDimitry Andric StructuredData::ObjectSP InstrumentationRuntimeTSan::RetrieveReportData( 3025ffd83dbSDimitry Andric ExecutionContextRef exe_ctx_ref) { 3035ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 3045ffd83dbSDimitry Andric if (!process_sp) 3055ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3065ffd83dbSDimitry Andric 3075ffd83dbSDimitry Andric ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); 30806c3fb27SDimitry Andric StackFrameSP frame_sp = 30906c3fb27SDimitry Andric thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); 3105ffd83dbSDimitry Andric 3115ffd83dbSDimitry Andric if (!frame_sp) 3125ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3135ffd83dbSDimitry Andric 3145ffd83dbSDimitry Andric EvaluateExpressionOptions options; 3155ffd83dbSDimitry Andric options.SetUnwindOnError(true); 3165ffd83dbSDimitry Andric options.SetTryAllThreads(true); 3175ffd83dbSDimitry Andric options.SetStopOthers(true); 3185ffd83dbSDimitry Andric options.SetIgnoreBreakpoints(true); 3195ffd83dbSDimitry Andric options.SetTimeout(process_sp->GetUtilityExpressionTimeout()); 3205ffd83dbSDimitry Andric options.SetPrefix(thread_sanitizer_retrieve_report_data_prefix); 3215ffd83dbSDimitry Andric options.SetAutoApplyFixIts(false); 3225ffd83dbSDimitry Andric options.SetLanguage(eLanguageTypeObjC_plus_plus); 3235ffd83dbSDimitry Andric 3245ffd83dbSDimitry Andric ValueObjectSP main_value; 3255ffd83dbSDimitry Andric ExecutionContext exe_ctx; 3265ffd83dbSDimitry Andric Status eval_error; 3275ffd83dbSDimitry Andric frame_sp->CalculateExecutionContext(exe_ctx); 3285ffd83dbSDimitry Andric ExpressionResults result = UserExpression::Evaluate( 3295ffd83dbSDimitry Andric exe_ctx, options, thread_sanitizer_retrieve_report_data_command, "", 3305ffd83dbSDimitry Andric main_value, eval_error); 3315ffd83dbSDimitry Andric if (result != eExpressionCompleted) { 33281ad6265SDimitry Andric StreamString ss; 33381ad6265SDimitry Andric ss << "cannot evaluate ThreadSanitizer expression:\n"; 33481ad6265SDimitry Andric ss << eval_error.AsCString(); 33581ad6265SDimitry Andric Debugger::ReportWarning(ss.GetString().str(), 33681ad6265SDimitry Andric process_sp->GetTarget().GetDebugger().GetID()); 3375ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3385ffd83dbSDimitry Andric } 3395ffd83dbSDimitry Andric 3405ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> thread_id_map; 3415ffd83dbSDimitry Andric GetRenumberedThreadIds(process_sp, main_value, thread_id_map); 3425ffd83dbSDimitry Andric 343bdd1243dSDimitry Andric auto dict = std::make_shared<StructuredData::Dictionary>(); 3445ffd83dbSDimitry Andric dict->AddStringItem("instrumentation_class", "ThreadSanitizer"); 3455ffd83dbSDimitry Andric dict->AddStringItem("issue_type", 3465ffd83dbSDimitry Andric RetrieveString(main_value, process_sp, ".description")); 3475ffd83dbSDimitry Andric dict->AddIntegerItem("report_count", 3485ffd83dbSDimitry Andric main_value->GetValueForExpressionPath(".report_count") 3495ffd83dbSDimitry Andric ->GetValueAsUnsigned(0)); 350bdd1243dSDimitry Andric dict->AddItem("sleep_trace", CreateStackTrace( 351bdd1243dSDimitry Andric main_value, ".sleep_trace")); 3525ffd83dbSDimitry Andric 353bdd1243dSDimitry Andric StructuredData::ArraySP stacks = ConvertToStructuredArray( 3545ffd83dbSDimitry Andric main_value, ".stacks", ".stack_count", 355bdd1243dSDimitry Andric [thread_sp](const ValueObjectSP &o, 356bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3575ffd83dbSDimitry Andric dict->AddIntegerItem( 3585ffd83dbSDimitry Andric "index", 3595ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 360bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 3615ffd83dbSDimitry Andric // "stacks" happen on the current thread 3625ffd83dbSDimitry Andric dict->AddIntegerItem("thread_id", thread_sp->GetIndexID()); 3635ffd83dbSDimitry Andric }); 364bdd1243dSDimitry Andric dict->AddItem("stacks", stacks); 3655ffd83dbSDimitry Andric 366bdd1243dSDimitry Andric StructuredData::ArraySP mops = ConvertToStructuredArray( 3675ffd83dbSDimitry Andric main_value, ".mops", ".mop_count", 368bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 369bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3705ffd83dbSDimitry Andric dict->AddIntegerItem( 3715ffd83dbSDimitry Andric "index", 3725ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 3735ffd83dbSDimitry Andric dict->AddIntegerItem( 3745ffd83dbSDimitry Andric "thread_id", 3755ffd83dbSDimitry Andric Renumber( 3765ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 3775ffd83dbSDimitry Andric thread_id_map)); 3785ffd83dbSDimitry Andric dict->AddIntegerItem( 3795ffd83dbSDimitry Andric "size", 3805ffd83dbSDimitry Andric o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0)); 3815ffd83dbSDimitry Andric dict->AddBooleanItem( 3825ffd83dbSDimitry Andric "is_write", 3835ffd83dbSDimitry Andric o->GetValueForExpressionPath(".write")->GetValueAsUnsigned(0)); 3845ffd83dbSDimitry Andric dict->AddBooleanItem( 3855ffd83dbSDimitry Andric "is_atomic", 3865ffd83dbSDimitry Andric o->GetValueForExpressionPath(".atomic")->GetValueAsUnsigned(0)); 3875ffd83dbSDimitry Andric dict->AddIntegerItem( 3885ffd83dbSDimitry Andric "address", 3895ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 390bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 3915ffd83dbSDimitry Andric }); 392bdd1243dSDimitry Andric dict->AddItem("mops", mops); 3935ffd83dbSDimitry Andric 394bdd1243dSDimitry Andric StructuredData::ArraySP locs = ConvertToStructuredArray( 3955ffd83dbSDimitry Andric main_value, ".locs", ".loc_count", 396bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 397bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3985ffd83dbSDimitry Andric dict->AddIntegerItem( 3995ffd83dbSDimitry Andric "index", 4005ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4015ffd83dbSDimitry Andric dict->AddStringItem("type", RetrieveString(o, process_sp, ".type")); 4025ffd83dbSDimitry Andric dict->AddIntegerItem( 4035ffd83dbSDimitry Andric "address", 4045ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 4055ffd83dbSDimitry Andric dict->AddIntegerItem( 4065ffd83dbSDimitry Andric "start", 4075ffd83dbSDimitry Andric o->GetValueForExpressionPath(".start")->GetValueAsUnsigned(0)); 4085ffd83dbSDimitry Andric dict->AddIntegerItem( 4095ffd83dbSDimitry Andric "size", 4105ffd83dbSDimitry Andric o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0)); 4115ffd83dbSDimitry Andric dict->AddIntegerItem( 4125ffd83dbSDimitry Andric "thread_id", 4135ffd83dbSDimitry Andric Renumber( 4145ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4155ffd83dbSDimitry Andric thread_id_map)); 4165ffd83dbSDimitry Andric dict->AddIntegerItem( 4175ffd83dbSDimitry Andric "file_descriptor", 4185ffd83dbSDimitry Andric o->GetValueForExpressionPath(".fd")->GetValueAsUnsigned(0)); 4195ffd83dbSDimitry Andric dict->AddIntegerItem("suppressable", 4205ffd83dbSDimitry Andric o->GetValueForExpressionPath(".suppressable") 4215ffd83dbSDimitry Andric ->GetValueAsUnsigned(0)); 422bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4235ffd83dbSDimitry Andric dict->AddStringItem("object_type", 4245ffd83dbSDimitry Andric RetrieveString(o, process_sp, ".object_type")); 4255ffd83dbSDimitry Andric }); 426bdd1243dSDimitry Andric dict->AddItem("locs", locs); 4275ffd83dbSDimitry Andric 428bdd1243dSDimitry Andric StructuredData::ArraySP mutexes = ConvertToStructuredArray( 4295ffd83dbSDimitry Andric main_value, ".mutexes", ".mutex_count", 430bdd1243dSDimitry Andric [](const ValueObjectSP &o, const StructuredData::DictionarySP &dict) { 4315ffd83dbSDimitry Andric dict->AddIntegerItem( 4325ffd83dbSDimitry Andric "index", 4335ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4345ffd83dbSDimitry Andric dict->AddIntegerItem( 4355ffd83dbSDimitry Andric "mutex_id", 4365ffd83dbSDimitry Andric o->GetValueForExpressionPath(".mutex_id")->GetValueAsUnsigned(0)); 4375ffd83dbSDimitry Andric dict->AddIntegerItem( 4385ffd83dbSDimitry Andric "address", 4395ffd83dbSDimitry Andric o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0)); 4405ffd83dbSDimitry Andric dict->AddIntegerItem( 4415ffd83dbSDimitry Andric "destroyed", 4425ffd83dbSDimitry Andric o->GetValueForExpressionPath(".destroyed")->GetValueAsUnsigned(0)); 443bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4445ffd83dbSDimitry Andric }); 445bdd1243dSDimitry Andric dict->AddItem("mutexes", mutexes); 4465ffd83dbSDimitry Andric 447bdd1243dSDimitry Andric StructuredData::ArraySP threads = ConvertToStructuredArray( 4485ffd83dbSDimitry Andric main_value, ".threads", ".thread_count", 449bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 450bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 4515ffd83dbSDimitry Andric dict->AddIntegerItem( 4525ffd83dbSDimitry Andric "index", 4535ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4545ffd83dbSDimitry Andric dict->AddIntegerItem( 4555ffd83dbSDimitry Andric "thread_id", 4565ffd83dbSDimitry Andric Renumber( 4575ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4585ffd83dbSDimitry Andric thread_id_map)); 4595ffd83dbSDimitry Andric dict->AddIntegerItem( 4605ffd83dbSDimitry Andric "thread_os_id", 4615ffd83dbSDimitry Andric o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0)); 4625ffd83dbSDimitry Andric dict->AddIntegerItem( 4635ffd83dbSDimitry Andric "running", 4645ffd83dbSDimitry Andric o->GetValueForExpressionPath(".running")->GetValueAsUnsigned(0)); 4655ffd83dbSDimitry Andric dict->AddStringItem("name", RetrieveString(o, process_sp, ".name")); 4665ffd83dbSDimitry Andric dict->AddIntegerItem( 4675ffd83dbSDimitry Andric "parent_thread_id", 4685ffd83dbSDimitry Andric Renumber(o->GetValueForExpressionPath(".parent_tid") 4695ffd83dbSDimitry Andric ->GetValueAsUnsigned(0), 4705ffd83dbSDimitry Andric thread_id_map)); 471bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4725ffd83dbSDimitry Andric }); 473bdd1243dSDimitry Andric dict->AddItem("threads", threads); 4745ffd83dbSDimitry Andric 475bdd1243dSDimitry Andric StructuredData::ArraySP unique_tids = ConvertToStructuredArray( 4765ffd83dbSDimitry Andric main_value, ".unique_tids", ".unique_tid_count", 477bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 478bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 4795ffd83dbSDimitry Andric dict->AddIntegerItem( 4805ffd83dbSDimitry Andric "index", 4815ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 4825ffd83dbSDimitry Andric dict->AddIntegerItem( 4835ffd83dbSDimitry Andric "tid", 4845ffd83dbSDimitry Andric Renumber( 4855ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), 4865ffd83dbSDimitry Andric thread_id_map)); 4875ffd83dbSDimitry Andric }); 488bdd1243dSDimitry Andric dict->AddItem("unique_tids", unique_tids); 4895ffd83dbSDimitry Andric 490bdd1243dSDimitry Andric return dict; 4915ffd83dbSDimitry Andric } 4925ffd83dbSDimitry Andric 4935ffd83dbSDimitry Andric std::string 4945ffd83dbSDimitry Andric InstrumentationRuntimeTSan::FormatDescription(StructuredData::ObjectSP report) { 4955ffd83dbSDimitry Andric std::string description = std::string(report->GetAsDictionary() 4965ffd83dbSDimitry Andric ->GetValueForKey("issue_type") 4975ffd83dbSDimitry Andric ->GetAsString() 4985ffd83dbSDimitry Andric ->GetValue()); 4995ffd83dbSDimitry Andric 5005ffd83dbSDimitry Andric if (description == "data-race") { 5015ffd83dbSDimitry Andric return "Data race"; 5025ffd83dbSDimitry Andric } else if (description == "data-race-vptr") { 5035ffd83dbSDimitry Andric return "Data race on C++ virtual pointer"; 5045ffd83dbSDimitry Andric } else if (description == "heap-use-after-free") { 5055ffd83dbSDimitry Andric return "Use of deallocated memory"; 5065ffd83dbSDimitry Andric } else if (description == "heap-use-after-free-vptr") { 5075ffd83dbSDimitry Andric return "Use of deallocated C++ virtual pointer"; 5085ffd83dbSDimitry Andric } else if (description == "thread-leak") { 5095ffd83dbSDimitry Andric return "Thread leak"; 5105ffd83dbSDimitry Andric } else if (description == "locked-mutex-destroy") { 5115ffd83dbSDimitry Andric return "Destruction of a locked mutex"; 5125ffd83dbSDimitry Andric } else if (description == "mutex-double-lock") { 5135ffd83dbSDimitry Andric return "Double lock of a mutex"; 5145ffd83dbSDimitry Andric } else if (description == "mutex-invalid-access") { 5155ffd83dbSDimitry Andric return "Use of an uninitialized or destroyed mutex"; 5165ffd83dbSDimitry Andric } else if (description == "mutex-bad-unlock") { 5175ffd83dbSDimitry Andric return "Unlock of an unlocked mutex (or by a wrong thread)"; 5185ffd83dbSDimitry Andric } else if (description == "mutex-bad-read-lock") { 5195ffd83dbSDimitry Andric return "Read lock of a write locked mutex"; 5205ffd83dbSDimitry Andric } else if (description == "mutex-bad-read-unlock") { 5215ffd83dbSDimitry Andric return "Read unlock of a write locked mutex"; 5225ffd83dbSDimitry Andric } else if (description == "signal-unsafe-call") { 5235ffd83dbSDimitry Andric return "Signal-unsafe call inside a signal handler"; 5245ffd83dbSDimitry Andric } else if (description == "errno-in-signal-handler") { 5255ffd83dbSDimitry Andric return "Overwrite of errno in a signal handler"; 5265ffd83dbSDimitry Andric } else if (description == "lock-order-inversion") { 5275ffd83dbSDimitry Andric return "Lock order inversion (potential deadlock)"; 5285ffd83dbSDimitry Andric } else if (description == "external-race") { 5295ffd83dbSDimitry Andric return "Race on a library object"; 5305ffd83dbSDimitry Andric } else if (description == "swift-access-race") { 5315ffd83dbSDimitry Andric return "Swift access race"; 5325ffd83dbSDimitry Andric } 5335ffd83dbSDimitry Andric 5345ffd83dbSDimitry Andric // for unknown report codes just show the code 5355ffd83dbSDimitry Andric return description; 5365ffd83dbSDimitry Andric } 5375ffd83dbSDimitry Andric 5385ffd83dbSDimitry Andric static std::string Sprintf(const char *format, ...) { 5395ffd83dbSDimitry Andric StreamString s; 5405ffd83dbSDimitry Andric va_list args; 5415ffd83dbSDimitry Andric va_start(args, format); 5425ffd83dbSDimitry Andric s.PrintfVarArg(format, args); 5435ffd83dbSDimitry Andric va_end(args); 5445ffd83dbSDimitry Andric return std::string(s.GetString()); 5455ffd83dbSDimitry Andric } 5465ffd83dbSDimitry Andric 5475ffd83dbSDimitry Andric static std::string GetSymbolNameFromAddress(ProcessSP process_sp, addr_t addr) { 5485ffd83dbSDimitry Andric lldb_private::Address so_addr; 5495ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, 5505ffd83dbSDimitry Andric so_addr)) 5515ffd83dbSDimitry Andric return ""; 5525ffd83dbSDimitry Andric 5535ffd83dbSDimitry Andric lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol(); 5545ffd83dbSDimitry Andric if (!symbol) 5555ffd83dbSDimitry Andric return ""; 5565ffd83dbSDimitry Andric 5575ffd83dbSDimitry Andric std::string sym_name = symbol->GetName().GetCString(); 5585ffd83dbSDimitry Andric return sym_name; 5595ffd83dbSDimitry Andric } 5605ffd83dbSDimitry Andric 5615ffd83dbSDimitry Andric static void GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, 5625ffd83dbSDimitry Andric Declaration &decl) { 5635ffd83dbSDimitry Andric lldb_private::Address so_addr; 5645ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, 5655ffd83dbSDimitry Andric so_addr)) 5665ffd83dbSDimitry Andric return; 5675ffd83dbSDimitry Andric 5685ffd83dbSDimitry Andric lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol(); 5695ffd83dbSDimitry Andric if (!symbol) 5705ffd83dbSDimitry Andric return; 5715ffd83dbSDimitry Andric 5725ffd83dbSDimitry Andric ConstString sym_name = symbol->GetMangled().GetName(Mangled::ePreferMangled); 5735ffd83dbSDimitry Andric 5745ffd83dbSDimitry Andric ModuleSP module = symbol->CalculateSymbolContextModule(); 5755ffd83dbSDimitry Andric if (!module) 5765ffd83dbSDimitry Andric return; 5775ffd83dbSDimitry Andric 5785ffd83dbSDimitry Andric VariableList var_list; 5795ffd83dbSDimitry Andric module->FindGlobalVariables(sym_name, CompilerDeclContext(), 1U, var_list); 5805ffd83dbSDimitry Andric if (var_list.GetSize() < 1) 5815ffd83dbSDimitry Andric return; 5825ffd83dbSDimitry Andric 5835ffd83dbSDimitry Andric VariableSP var = var_list.GetVariableAtIndex(0); 5845ffd83dbSDimitry Andric decl = var->GetDeclaration(); 5855ffd83dbSDimitry Andric } 5865ffd83dbSDimitry Andric 5875ffd83dbSDimitry Andric addr_t InstrumentationRuntimeTSan::GetFirstNonInternalFramePc( 5885ffd83dbSDimitry Andric StructuredData::ObjectSP trace, bool skip_one_frame) { 5895ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 5905ffd83dbSDimitry Andric ModuleSP runtime_module_sp = GetRuntimeModuleSP(); 5915ffd83dbSDimitry Andric 5925ffd83dbSDimitry Andric StructuredData::Array *trace_array = trace->GetAsArray(); 5935ffd83dbSDimitry Andric for (size_t i = 0; i < trace_array->GetSize(); i++) { 5945ffd83dbSDimitry Andric if (skip_one_frame && i == 0) 5955ffd83dbSDimitry Andric continue; 5965ffd83dbSDimitry Andric 5971db9f3b2SDimitry Andric auto maybe_addr = trace_array->GetItemAtIndexAsInteger<addr_t>(i); 5981db9f3b2SDimitry Andric if (!maybe_addr) 5995ffd83dbSDimitry Andric continue; 6001db9f3b2SDimitry Andric addr_t addr = *maybe_addr; 6015ffd83dbSDimitry Andric 6025ffd83dbSDimitry Andric lldb_private::Address so_addr; 6035ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( 6045ffd83dbSDimitry Andric addr, so_addr)) 6055ffd83dbSDimitry Andric continue; 6065ffd83dbSDimitry Andric 6075ffd83dbSDimitry Andric if (so_addr.GetModule() == runtime_module_sp) 6085ffd83dbSDimitry Andric continue; 6095ffd83dbSDimitry Andric 6105ffd83dbSDimitry Andric return addr; 6115ffd83dbSDimitry Andric } 6125ffd83dbSDimitry Andric 6135ffd83dbSDimitry Andric return 0; 6145ffd83dbSDimitry Andric } 6155ffd83dbSDimitry Andric 6165ffd83dbSDimitry Andric std::string 6175ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GenerateSummary(StructuredData::ObjectSP report) { 6185ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 6195ffd83dbSDimitry Andric 6205ffd83dbSDimitry Andric std::string summary = std::string(report->GetAsDictionary() 6215ffd83dbSDimitry Andric ->GetValueForKey("description") 6225ffd83dbSDimitry Andric ->GetAsString() 6235ffd83dbSDimitry Andric ->GetValue()); 6245ffd83dbSDimitry Andric bool skip_one_frame = 6255ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("issue_type")->GetStringValue() == 6265ffd83dbSDimitry Andric "external-race"; 6275ffd83dbSDimitry Andric 6285ffd83dbSDimitry Andric addr_t pc = 0; 6295ffd83dbSDimitry Andric if (report->GetAsDictionary() 6305ffd83dbSDimitry Andric ->GetValueForKey("mops") 6315ffd83dbSDimitry Andric ->GetAsArray() 6325ffd83dbSDimitry Andric ->GetSize() > 0) 6335ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6345ffd83dbSDimitry Andric ->GetValueForKey("mops") 6355ffd83dbSDimitry Andric ->GetAsArray() 6365ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6375ffd83dbSDimitry Andric ->GetAsDictionary() 6385ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6395ffd83dbSDimitry Andric skip_one_frame); 6405ffd83dbSDimitry Andric 6415ffd83dbSDimitry Andric if (report->GetAsDictionary() 6425ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6435ffd83dbSDimitry Andric ->GetAsArray() 6445ffd83dbSDimitry Andric ->GetSize() > 0) 6455ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6465ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6475ffd83dbSDimitry Andric ->GetAsArray() 6485ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6495ffd83dbSDimitry Andric ->GetAsDictionary() 6505ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6515ffd83dbSDimitry Andric skip_one_frame); 6525ffd83dbSDimitry Andric 6535ffd83dbSDimitry Andric if (pc != 0) { 6545ffd83dbSDimitry Andric summary = summary + " in " + GetSymbolNameFromAddress(process_sp, pc); 6555ffd83dbSDimitry Andric } 6565ffd83dbSDimitry Andric 6575ffd83dbSDimitry Andric if (report->GetAsDictionary() 6585ffd83dbSDimitry Andric ->GetValueForKey("locs") 6595ffd83dbSDimitry Andric ->GetAsArray() 6605ffd83dbSDimitry Andric ->GetSize() > 0) { 6615ffd83dbSDimitry Andric StructuredData::ObjectSP loc = report->GetAsDictionary() 6625ffd83dbSDimitry Andric ->GetValueForKey("locs") 6635ffd83dbSDimitry Andric ->GetAsArray() 6645ffd83dbSDimitry Andric ->GetItemAtIndex(0); 6655ffd83dbSDimitry Andric std::string object_type = std::string(loc->GetAsDictionary() 6665ffd83dbSDimitry Andric ->GetValueForKey("object_type") 6675ffd83dbSDimitry Andric ->GetAsString() 6685ffd83dbSDimitry Andric ->GetValue()); 6695ffd83dbSDimitry Andric if (!object_type.empty()) { 6705ffd83dbSDimitry Andric summary = "Race on " + object_type + " object"; 6715ffd83dbSDimitry Andric } 6725ffd83dbSDimitry Andric addr_t addr = loc->GetAsDictionary() 6735ffd83dbSDimitry Andric ->GetValueForKey("address") 67406c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 6755ffd83dbSDimitry Andric if (addr == 0) 6765ffd83dbSDimitry Andric addr = loc->GetAsDictionary() 6775ffd83dbSDimitry Andric ->GetValueForKey("start") 67806c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 6795ffd83dbSDimitry Andric 6805ffd83dbSDimitry Andric if (addr != 0) { 6815ffd83dbSDimitry Andric std::string global_name = GetSymbolNameFromAddress(process_sp, addr); 6825ffd83dbSDimitry Andric if (!global_name.empty()) { 6835ffd83dbSDimitry Andric summary = summary + " at " + global_name; 6845ffd83dbSDimitry Andric } else { 6855ffd83dbSDimitry Andric summary = summary + " at " + Sprintf("0x%llx", addr); 6865ffd83dbSDimitry Andric } 6875ffd83dbSDimitry Andric } else { 6885ffd83dbSDimitry Andric int fd = loc->GetAsDictionary() 6895ffd83dbSDimitry Andric ->GetValueForKey("file_descriptor") 69006c3fb27SDimitry Andric ->GetSignedIntegerValue(); 6915ffd83dbSDimitry Andric if (fd != 0) { 6925ffd83dbSDimitry Andric summary = summary + " on file descriptor " + Sprintf("%d", fd); 6935ffd83dbSDimitry Andric } 6945ffd83dbSDimitry Andric } 6955ffd83dbSDimitry Andric } 6965ffd83dbSDimitry Andric 6975ffd83dbSDimitry Andric return summary; 6985ffd83dbSDimitry Andric } 6995ffd83dbSDimitry Andric 7005ffd83dbSDimitry Andric addr_t InstrumentationRuntimeTSan::GetMainRacyAddress( 7015ffd83dbSDimitry Andric StructuredData::ObjectSP report) { 7025ffd83dbSDimitry Andric addr_t result = (addr_t)-1; 7035ffd83dbSDimitry Andric 7045ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach( 7055ffd83dbSDimitry Andric [&result](StructuredData::Object *o) -> bool { 70606c3fb27SDimitry Andric addr_t addr = o->GetObjectForDotSeparatedPath("address") 70706c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 7085ffd83dbSDimitry Andric if (addr < result) 7095ffd83dbSDimitry Andric result = addr; 7105ffd83dbSDimitry Andric return true; 7115ffd83dbSDimitry Andric }); 7125ffd83dbSDimitry Andric 7135ffd83dbSDimitry Andric return (result == (addr_t)-1) ? 0 : result; 7145ffd83dbSDimitry Andric } 7155ffd83dbSDimitry Andric 7165ffd83dbSDimitry Andric std::string InstrumentationRuntimeTSan::GetLocationDescription( 7175ffd83dbSDimitry Andric StructuredData::ObjectSP report, addr_t &global_addr, 7185ffd83dbSDimitry Andric std::string &global_name, std::string &filename, uint32_t &line) { 71904eeddc0SDimitry Andric std::string result; 7205ffd83dbSDimitry Andric 7215ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 7225ffd83dbSDimitry Andric 7235ffd83dbSDimitry Andric if (report->GetAsDictionary() 7245ffd83dbSDimitry Andric ->GetValueForKey("locs") 7255ffd83dbSDimitry Andric ->GetAsArray() 7265ffd83dbSDimitry Andric ->GetSize() > 0) { 7275ffd83dbSDimitry Andric StructuredData::ObjectSP loc = report->GetAsDictionary() 7285ffd83dbSDimitry Andric ->GetValueForKey("locs") 7295ffd83dbSDimitry Andric ->GetAsArray() 7305ffd83dbSDimitry Andric ->GetItemAtIndex(0); 7315ffd83dbSDimitry Andric std::string type = std::string( 7325ffd83dbSDimitry Andric loc->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); 7335ffd83dbSDimitry Andric if (type == "global") { 7345ffd83dbSDimitry Andric global_addr = loc->GetAsDictionary() 7355ffd83dbSDimitry Andric ->GetValueForKey("address") 73606c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 73706c3fb27SDimitry Andric 7385ffd83dbSDimitry Andric global_name = GetSymbolNameFromAddress(process_sp, global_addr); 7395ffd83dbSDimitry Andric if (!global_name.empty()) { 7405ffd83dbSDimitry Andric result = Sprintf("'%s' is a global variable (0x%llx)", 7415ffd83dbSDimitry Andric global_name.c_str(), global_addr); 7425ffd83dbSDimitry Andric } else { 7435ffd83dbSDimitry Andric result = Sprintf("0x%llx is a global variable", global_addr); 7445ffd83dbSDimitry Andric } 7455ffd83dbSDimitry Andric 7465ffd83dbSDimitry Andric Declaration decl; 7475ffd83dbSDimitry Andric GetSymbolDeclarationFromAddress(process_sp, global_addr, decl); 7485ffd83dbSDimitry Andric if (decl.GetFile()) { 7495ffd83dbSDimitry Andric filename = decl.GetFile().GetPath(); 7505ffd83dbSDimitry Andric line = decl.GetLine(); 7515ffd83dbSDimitry Andric } 7525ffd83dbSDimitry Andric } else if (type == "heap") { 7535ffd83dbSDimitry Andric addr_t addr = loc->GetAsDictionary() 7545ffd83dbSDimitry Andric ->GetValueForKey("start") 75506c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 75606c3fb27SDimitry Andric 75706c3fb27SDimitry Andric size_t size = loc->GetAsDictionary() 7585ffd83dbSDimitry Andric ->GetValueForKey("size") 75906c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 76006c3fb27SDimitry Andric 7615ffd83dbSDimitry Andric std::string object_type = std::string(loc->GetAsDictionary() 7625ffd83dbSDimitry Andric ->GetValueForKey("object_type") 7635ffd83dbSDimitry Andric ->GetAsString() 7645ffd83dbSDimitry Andric ->GetValue()); 7655ffd83dbSDimitry Andric if (!object_type.empty()) { 7665ffd83dbSDimitry Andric result = Sprintf("Location is a %ld-byte %s object at 0x%llx", size, 7675ffd83dbSDimitry Andric object_type.c_str(), addr); 7685ffd83dbSDimitry Andric } else { 7695ffd83dbSDimitry Andric result = 7705ffd83dbSDimitry Andric Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr); 7715ffd83dbSDimitry Andric } 7725ffd83dbSDimitry Andric } else if (type == "stack") { 77306c3fb27SDimitry Andric tid_t tid = loc->GetAsDictionary() 7745ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 77506c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 77606c3fb27SDimitry Andric 7775ffd83dbSDimitry Andric result = Sprintf("Location is stack of thread %d", tid); 7785ffd83dbSDimitry Andric } else if (type == "tls") { 77906c3fb27SDimitry Andric tid_t tid = loc->GetAsDictionary() 7805ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 78106c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 78206c3fb27SDimitry Andric 7835ffd83dbSDimitry Andric result = Sprintf("Location is TLS of thread %d", tid); 7845ffd83dbSDimitry Andric } else if (type == "fd") { 7855ffd83dbSDimitry Andric int fd = loc->GetAsDictionary() 7865ffd83dbSDimitry Andric ->GetValueForKey("file_descriptor") 78706c3fb27SDimitry Andric ->GetSignedIntegerValue(); 78806c3fb27SDimitry Andric 7895ffd83dbSDimitry Andric result = Sprintf("Location is file descriptor %d", fd); 7905ffd83dbSDimitry Andric } 7915ffd83dbSDimitry Andric } 7925ffd83dbSDimitry Andric 7935ffd83dbSDimitry Andric return result; 7945ffd83dbSDimitry Andric } 7955ffd83dbSDimitry Andric 7965ffd83dbSDimitry Andric bool InstrumentationRuntimeTSan::NotifyBreakpointHit( 7975ffd83dbSDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 7985ffd83dbSDimitry Andric user_id_t break_loc_id) { 7995ffd83dbSDimitry Andric assert(baton && "null baton"); 8005ffd83dbSDimitry Andric if (!baton) 8015ffd83dbSDimitry Andric return false; 8025ffd83dbSDimitry Andric 8035ffd83dbSDimitry Andric InstrumentationRuntimeTSan *const instance = 8045ffd83dbSDimitry Andric static_cast<InstrumentationRuntimeTSan *>(baton); 8055ffd83dbSDimitry Andric 8065ffd83dbSDimitry Andric ProcessSP process_sp = instance->GetProcessSP(); 8075ffd83dbSDimitry Andric 8085ffd83dbSDimitry Andric if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) 8095ffd83dbSDimitry Andric return false; 8105ffd83dbSDimitry Andric 8115ffd83dbSDimitry Andric StructuredData::ObjectSP report = 8125ffd83dbSDimitry Andric instance->RetrieveReportData(context->exe_ctx_ref); 813e8d8bef9SDimitry Andric std::string stop_reason_description = 814e8d8bef9SDimitry Andric "unknown thread sanitizer fault (unable to extract thread sanitizer " 815e8d8bef9SDimitry Andric "report)"; 8165ffd83dbSDimitry Andric if (report) { 8175ffd83dbSDimitry Andric std::string issue_description = instance->FormatDescription(report); 8185ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("description", issue_description); 8195ffd83dbSDimitry Andric stop_reason_description = issue_description + " detected"; 8205ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("stop_description", 8215ffd83dbSDimitry Andric stop_reason_description); 8225ffd83dbSDimitry Andric std::string summary = instance->GenerateSummary(report); 8235ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("summary", summary); 8245ffd83dbSDimitry Andric addr_t main_address = instance->GetMainRacyAddress(report); 8255ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("memory_address", main_address); 8265ffd83dbSDimitry Andric 8275ffd83dbSDimitry Andric addr_t global_addr = 0; 82804eeddc0SDimitry Andric std::string global_name; 82904eeddc0SDimitry Andric std::string location_filename; 8305ffd83dbSDimitry Andric uint32_t location_line = 0; 8315ffd83dbSDimitry Andric std::string location_description = instance->GetLocationDescription( 8325ffd83dbSDimitry Andric report, global_addr, global_name, location_filename, location_line); 8335ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("location_description", 8345ffd83dbSDimitry Andric location_description); 8355ffd83dbSDimitry Andric if (global_addr != 0) { 8365ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("global_address", global_addr); 8375ffd83dbSDimitry Andric } 8385ffd83dbSDimitry Andric if (!global_name.empty()) { 8395ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("global_name", global_name); 8405ffd83dbSDimitry Andric } 8415ffd83dbSDimitry Andric if (location_filename != "") { 8425ffd83dbSDimitry Andric report->GetAsDictionary()->AddStringItem("location_filename", 8435ffd83dbSDimitry Andric location_filename); 8445ffd83dbSDimitry Andric report->GetAsDictionary()->AddIntegerItem("location_line", location_line); 8455ffd83dbSDimitry Andric } 8465ffd83dbSDimitry Andric 8475ffd83dbSDimitry Andric bool all_addresses_are_same = true; 8485ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach( 8495ffd83dbSDimitry Andric [&all_addresses_are_same, 8505ffd83dbSDimitry Andric main_address](StructuredData::Object *o) -> bool { 85106c3fb27SDimitry Andric addr_t addr = o->GetObjectForDotSeparatedPath("address") 85206c3fb27SDimitry Andric ->GetUnsignedIntegerValue(); 8535ffd83dbSDimitry Andric if (main_address != addr) 8545ffd83dbSDimitry Andric all_addresses_are_same = false; 8555ffd83dbSDimitry Andric return true; 8565ffd83dbSDimitry Andric }); 8575ffd83dbSDimitry Andric report->GetAsDictionary()->AddBooleanItem("all_addresses_are_same", 8585ffd83dbSDimitry Andric all_addresses_are_same); 8595ffd83dbSDimitry Andric } 8605ffd83dbSDimitry Andric 8615ffd83dbSDimitry Andric // Make sure this is the right process 8625ffd83dbSDimitry Andric if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP()) { 8635ffd83dbSDimitry Andric ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); 8645ffd83dbSDimitry Andric if (thread_sp) 8655ffd83dbSDimitry Andric thread_sp->SetStopInfo( 8665ffd83dbSDimitry Andric InstrumentationRuntimeStopInfo:: 8675ffd83dbSDimitry Andric CreateStopReasonWithInstrumentationData( 8685ffd83dbSDimitry Andric *thread_sp, stop_reason_description, report)); 8695ffd83dbSDimitry Andric 8705ffd83dbSDimitry Andric StreamFile &s = process_sp->GetTarget().GetDebugger().GetOutputStream(); 8715ffd83dbSDimitry Andric s.Printf("ThreadSanitizer report breakpoint hit. Use 'thread " 8725ffd83dbSDimitry Andric "info -s' to get extended information about the " 8735ffd83dbSDimitry Andric "report.\n"); 8745ffd83dbSDimitry Andric 8755ffd83dbSDimitry Andric return true; // Return true to stop the target 8765ffd83dbSDimitry Andric } else 8775ffd83dbSDimitry Andric return false; // Let target run 8785ffd83dbSDimitry Andric } 8795ffd83dbSDimitry Andric 8805ffd83dbSDimitry Andric const RegularExpression & 8815ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GetPatternForRuntimeLibrary() { 8825ffd83dbSDimitry Andric static RegularExpression regex(llvm::StringRef("libclang_rt.tsan_")); 8835ffd83dbSDimitry Andric return regex; 8845ffd83dbSDimitry Andric } 8855ffd83dbSDimitry Andric 8865ffd83dbSDimitry Andric bool InstrumentationRuntimeTSan::CheckIfRuntimeIsValid( 8875ffd83dbSDimitry Andric const lldb::ModuleSP module_sp) { 8885ffd83dbSDimitry Andric static ConstString g_tsan_get_current_report("__tsan_get_current_report"); 8895ffd83dbSDimitry Andric const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( 8905ffd83dbSDimitry Andric g_tsan_get_current_report, lldb::eSymbolTypeAny); 8915ffd83dbSDimitry Andric return symbol != nullptr; 8925ffd83dbSDimitry Andric } 8935ffd83dbSDimitry Andric 8945ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Activate() { 8955ffd83dbSDimitry Andric if (IsActive()) 8965ffd83dbSDimitry Andric return; 8975ffd83dbSDimitry Andric 8985ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 8995ffd83dbSDimitry Andric if (!process_sp) 9005ffd83dbSDimitry Andric return; 9015ffd83dbSDimitry Andric 9025ffd83dbSDimitry Andric ConstString symbol_name("__tsan_on_report"); 9035ffd83dbSDimitry Andric const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType( 9045ffd83dbSDimitry Andric symbol_name, eSymbolTypeCode); 9055ffd83dbSDimitry Andric 9065ffd83dbSDimitry Andric if (symbol == nullptr) 9075ffd83dbSDimitry Andric return; 9085ffd83dbSDimitry Andric 9095ffd83dbSDimitry Andric if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) 9105ffd83dbSDimitry Andric return; 9115ffd83dbSDimitry Andric 9125ffd83dbSDimitry Andric Target &target = process_sp->GetTarget(); 9135ffd83dbSDimitry Andric addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); 9145ffd83dbSDimitry Andric 9155ffd83dbSDimitry Andric if (symbol_address == LLDB_INVALID_ADDRESS) 9165ffd83dbSDimitry Andric return; 9175ffd83dbSDimitry Andric 918bdd1243dSDimitry Andric const bool internal = true; 919bdd1243dSDimitry Andric const bool hardware = false; 920bdd1243dSDimitry Andric const bool sync = false; 9215ffd83dbSDimitry Andric Breakpoint *breakpoint = 9225ffd83dbSDimitry Andric process_sp->GetTarget() 9235ffd83dbSDimitry Andric .CreateBreakpoint(symbol_address, internal, hardware) 9245ffd83dbSDimitry Andric .get(); 9255ffd83dbSDimitry Andric breakpoint->SetCallback(InstrumentationRuntimeTSan::NotifyBreakpointHit, this, 926bdd1243dSDimitry Andric sync); 9275ffd83dbSDimitry Andric breakpoint->SetBreakpointKind("thread-sanitizer-report"); 9285ffd83dbSDimitry Andric SetBreakpointID(breakpoint->GetID()); 9295ffd83dbSDimitry Andric 9305ffd83dbSDimitry Andric SetActive(true); 9315ffd83dbSDimitry Andric } 9325ffd83dbSDimitry Andric 9335ffd83dbSDimitry Andric void InstrumentationRuntimeTSan::Deactivate() { 9345ffd83dbSDimitry Andric if (GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 9355ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 9365ffd83dbSDimitry Andric if (process_sp) { 9375ffd83dbSDimitry Andric process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID()); 9385ffd83dbSDimitry Andric SetBreakpointID(LLDB_INVALID_BREAK_ID); 9395ffd83dbSDimitry Andric } 9405ffd83dbSDimitry Andric } 9415ffd83dbSDimitry Andric SetActive(false); 9425ffd83dbSDimitry Andric } 9435ffd83dbSDimitry Andric static std::string GenerateThreadName(const std::string &path, 9445ffd83dbSDimitry Andric StructuredData::Object *o, 9455ffd83dbSDimitry Andric StructuredData::ObjectSP main_info) { 9465ffd83dbSDimitry Andric std::string result = "additional information"; 9475ffd83dbSDimitry Andric 9485ffd83dbSDimitry Andric if (path == "mops") { 94906c3fb27SDimitry Andric size_t size = 95006c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("size")->GetUnsignedIntegerValue(); 95106c3fb27SDimitry Andric tid_t thread_id = 95206c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 9535ffd83dbSDimitry Andric bool is_write = 9545ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); 9555ffd83dbSDimitry Andric bool is_atomic = 9565ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_atomic")->GetBooleanValue(); 95706c3fb27SDimitry Andric addr_t addr = 95806c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("address")->GetUnsignedIntegerValue(); 9595ffd83dbSDimitry Andric 9605ffd83dbSDimitry Andric std::string addr_string = Sprintf(" at 0x%llx", addr); 9615ffd83dbSDimitry Andric 9625ffd83dbSDimitry Andric if (main_info->GetObjectForDotSeparatedPath("all_addresses_are_same") 9635ffd83dbSDimitry Andric ->GetBooleanValue()) { 9645ffd83dbSDimitry Andric addr_string = ""; 9655ffd83dbSDimitry Andric } 9665ffd83dbSDimitry Andric 9675ffd83dbSDimitry Andric if (main_info->GetObjectForDotSeparatedPath("issue_type") 9685ffd83dbSDimitry Andric ->GetStringValue() == "external-race") { 9695ffd83dbSDimitry Andric result = Sprintf("%s access by thread %d", 9705ffd83dbSDimitry Andric is_write ? "mutating" : "read-only", thread_id); 9715ffd83dbSDimitry Andric } else if (main_info->GetObjectForDotSeparatedPath("issue_type") 9725ffd83dbSDimitry Andric ->GetStringValue() == "swift-access-race") { 9735ffd83dbSDimitry Andric result = Sprintf("modifying access by thread %d", thread_id); 9745ffd83dbSDimitry Andric } else { 97506c3fb27SDimitry Andric result = Sprintf("%s%s of size %zu%s by thread %" PRIu64, 9765ffd83dbSDimitry Andric is_atomic ? "atomic " : "", is_write ? "write" : "read", 9775ffd83dbSDimitry Andric size, addr_string.c_str(), thread_id); 9785ffd83dbSDimitry Andric } 9795ffd83dbSDimitry Andric } 9805ffd83dbSDimitry Andric 9815ffd83dbSDimitry Andric if (path == "threads") { 98206c3fb27SDimitry Andric tid_t thread_id = 98306c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 98406c3fb27SDimitry Andric result = Sprintf("Thread %zu created", thread_id); 9855ffd83dbSDimitry Andric } 9865ffd83dbSDimitry Andric 9875ffd83dbSDimitry Andric if (path == "locs") { 9885ffd83dbSDimitry Andric std::string type = std::string( 9895ffd83dbSDimitry Andric o->GetAsDictionary()->GetValueForKey("type")->GetStringValue()); 99006c3fb27SDimitry Andric tid_t thread_id = 99106c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 99206c3fb27SDimitry Andric int fd = o->GetObjectForDotSeparatedPath("file_descriptor") 99306c3fb27SDimitry Andric ->GetSignedIntegerValue(); 9945ffd83dbSDimitry Andric if (type == "heap") { 99506c3fb27SDimitry Andric result = Sprintf("Heap block allocated by thread %" PRIu64, thread_id); 9965ffd83dbSDimitry Andric } else if (type == "fd") { 99706c3fb27SDimitry Andric result = Sprintf("File descriptor %d created by thread %" PRIu64, fd, 99806c3fb27SDimitry Andric thread_id); 9995ffd83dbSDimitry Andric } 10005ffd83dbSDimitry Andric } 10015ffd83dbSDimitry Andric 10025ffd83dbSDimitry Andric if (path == "mutexes") { 10035ffd83dbSDimitry Andric int mutex_id = 100406c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("mutex_id")->GetSignedIntegerValue(); 10055ffd83dbSDimitry Andric 10065ffd83dbSDimitry Andric result = Sprintf("Mutex M%d created", mutex_id); 10075ffd83dbSDimitry Andric } 10085ffd83dbSDimitry Andric 10095ffd83dbSDimitry Andric if (path == "stacks") { 101006c3fb27SDimitry Andric tid_t thread_id = 101106c3fb27SDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetUnsignedIntegerValue(); 101206c3fb27SDimitry Andric result = Sprintf("Thread %" PRIu64, thread_id); 10135ffd83dbSDimitry Andric } 10145ffd83dbSDimitry Andric 10155ffd83dbSDimitry Andric result[0] = toupper(result[0]); 10165ffd83dbSDimitry Andric 10175ffd83dbSDimitry Andric return result; 10185ffd83dbSDimitry Andric } 10195ffd83dbSDimitry Andric 10205ffd83dbSDimitry Andric static void AddThreadsForPath(const std::string &path, 10215ffd83dbSDimitry Andric ThreadCollectionSP threads, ProcessSP process_sp, 10225ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 10235ffd83dbSDimitry Andric info->GetObjectForDotSeparatedPath(path)->GetAsArray()->ForEach( 10245ffd83dbSDimitry Andric [process_sp, threads, path, info](StructuredData::Object *o) -> bool { 10255ffd83dbSDimitry Andric std::vector<lldb::addr_t> pcs; 10265ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("trace")->GetAsArray()->ForEach( 10275ffd83dbSDimitry Andric [&pcs](StructuredData::Object *pc) -> bool { 102806c3fb27SDimitry Andric pcs.push_back(pc->GetUnsignedIntegerValue()); 10295ffd83dbSDimitry Andric return true; 10305ffd83dbSDimitry Andric }); 10315ffd83dbSDimitry Andric 10325ffd83dbSDimitry Andric if (pcs.size() == 0) 10335ffd83dbSDimitry Andric return true; 10345ffd83dbSDimitry Andric 10355ffd83dbSDimitry Andric StructuredData::ObjectSP thread_id_obj = 10365ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_os_id"); 103706c3fb27SDimitry Andric tid_t tid = 103806c3fb27SDimitry Andric thread_id_obj ? thread_id_obj->GetUnsignedIntegerValue() : 0; 10395ffd83dbSDimitry Andric 1040bdd1243dSDimitry Andric ThreadSP new_thread_sp = 1041bdd1243dSDimitry Andric std::make_shared<HistoryThread>(*process_sp, tid, pcs); 10425ffd83dbSDimitry Andric new_thread_sp->SetName(GenerateThreadName(path, o, info).c_str()); 10435ffd83dbSDimitry Andric 10445ffd83dbSDimitry Andric // Save this in the Process' ExtendedThreadList so a strong pointer 10455ffd83dbSDimitry Andric // retains the object 10465ffd83dbSDimitry Andric process_sp->GetExtendedThreadList().AddThread(new_thread_sp); 10475ffd83dbSDimitry Andric threads->AddThread(new_thread_sp); 10485ffd83dbSDimitry Andric 10495ffd83dbSDimitry Andric return true; 10505ffd83dbSDimitry Andric }); 10515ffd83dbSDimitry Andric } 10525ffd83dbSDimitry Andric 10535ffd83dbSDimitry Andric lldb::ThreadCollectionSP 10545ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GetBacktracesFromExtendedStopInfo( 10555ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 1056bdd1243dSDimitry Andric 1057bdd1243dSDimitry Andric ThreadCollectionSP threads = std::make_shared<ThreadCollection>(); 10585ffd83dbSDimitry Andric 10595ffd83dbSDimitry Andric if (info->GetObjectForDotSeparatedPath("instrumentation_class") 10605ffd83dbSDimitry Andric ->GetStringValue() != "ThreadSanitizer") 10615ffd83dbSDimitry Andric return threads; 10625ffd83dbSDimitry Andric 10635ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 10645ffd83dbSDimitry Andric 10655ffd83dbSDimitry Andric AddThreadsForPath("stacks", threads, process_sp, info); 10665ffd83dbSDimitry Andric AddThreadsForPath("mops", threads, process_sp, info); 10675ffd83dbSDimitry Andric AddThreadsForPath("locs", threads, process_sp, info); 10685ffd83dbSDimitry Andric AddThreadsForPath("mutexes", threads, process_sp, info); 10695ffd83dbSDimitry Andric AddThreadsForPath("threads", threads, process_sp, info); 10705ffd83dbSDimitry Andric 10715ffd83dbSDimitry Andric return threads; 10725ffd83dbSDimitry Andric } 1073