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/StreamFile.h" 185ffd83dbSDimitry Andric #include "lldb/Core/ValueObject.h" 195ffd83dbSDimitry Andric #include "lldb/Expression/UserExpression.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 } 905ffd83dbSDimitry Andric 915ffd83dbSDimitry Andric const int REPORT_TRACE_SIZE = 128; 925ffd83dbSDimitry Andric const int REPORT_ARRAY_SIZE = 4; 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric struct data { 955ffd83dbSDimitry Andric void *report; 965ffd83dbSDimitry Andric const char *description; 975ffd83dbSDimitry Andric int report_count; 985ffd83dbSDimitry Andric 995ffd83dbSDimitry Andric void *sleep_trace[REPORT_TRACE_SIZE]; 1005ffd83dbSDimitry Andric 1015ffd83dbSDimitry Andric int stack_count; 1025ffd83dbSDimitry Andric struct { 1035ffd83dbSDimitry Andric int idx; 1045ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1055ffd83dbSDimitry Andric } stacks[REPORT_ARRAY_SIZE]; 1065ffd83dbSDimitry Andric 1075ffd83dbSDimitry Andric int mop_count; 1085ffd83dbSDimitry Andric struct { 1095ffd83dbSDimitry Andric int idx; 1105ffd83dbSDimitry Andric int tid; 1115ffd83dbSDimitry Andric int size; 1125ffd83dbSDimitry Andric int write; 1135ffd83dbSDimitry Andric int atomic; 1145ffd83dbSDimitry Andric void *addr; 1155ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1165ffd83dbSDimitry Andric } mops[REPORT_ARRAY_SIZE]; 1175ffd83dbSDimitry Andric 1185ffd83dbSDimitry Andric int loc_count; 1195ffd83dbSDimitry Andric struct { 1205ffd83dbSDimitry Andric int idx; 1215ffd83dbSDimitry Andric const char *type; 1225ffd83dbSDimitry Andric void *addr; 1235ffd83dbSDimitry Andric unsigned long start; 1245ffd83dbSDimitry Andric unsigned long size; 1255ffd83dbSDimitry Andric int tid; 1265ffd83dbSDimitry Andric int fd; 1275ffd83dbSDimitry Andric int suppressable; 1285ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1295ffd83dbSDimitry Andric const char *object_type; 1305ffd83dbSDimitry Andric } locs[REPORT_ARRAY_SIZE]; 1315ffd83dbSDimitry Andric 1325ffd83dbSDimitry Andric int mutex_count; 1335ffd83dbSDimitry Andric struct { 1345ffd83dbSDimitry Andric int idx; 1355ffd83dbSDimitry Andric unsigned long mutex_id; 1365ffd83dbSDimitry Andric void *addr; 1375ffd83dbSDimitry Andric int destroyed; 1385ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1395ffd83dbSDimitry Andric } mutexes[REPORT_ARRAY_SIZE]; 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric int thread_count; 1425ffd83dbSDimitry Andric struct { 1435ffd83dbSDimitry Andric int idx; 1445ffd83dbSDimitry Andric int tid; 1455ffd83dbSDimitry Andric unsigned long os_id; 1465ffd83dbSDimitry Andric int running; 1475ffd83dbSDimitry Andric const char *name; 1485ffd83dbSDimitry Andric int parent_tid; 1495ffd83dbSDimitry Andric void *trace[REPORT_TRACE_SIZE]; 1505ffd83dbSDimitry Andric } threads[REPORT_ARRAY_SIZE]; 1515ffd83dbSDimitry Andric 1525ffd83dbSDimitry Andric int unique_tid_count; 1535ffd83dbSDimitry Andric struct { 1545ffd83dbSDimitry Andric int idx; 1555ffd83dbSDimitry Andric int tid; 1565ffd83dbSDimitry Andric } unique_tids[REPORT_ARRAY_SIZE]; 1575ffd83dbSDimitry Andric }; 1585ffd83dbSDimitry Andric )"; 1595ffd83dbSDimitry Andric 1605ffd83dbSDimitry Andric const char *thread_sanitizer_retrieve_report_data_command = R"( 1615ffd83dbSDimitry Andric data t = {0}; 1625ffd83dbSDimitry Andric 1635ffd83dbSDimitry 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"); 1645ffd83dbSDimitry Andric 1655ffd83dbSDimitry Andric t.report = __tsan_get_current_report(); 1665ffd83dbSDimitry 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); 1675ffd83dbSDimitry Andric 1685ffd83dbSDimitry Andric if (t.stack_count > REPORT_ARRAY_SIZE) t.stack_count = REPORT_ARRAY_SIZE; 1695ffd83dbSDimitry Andric for (int i = 0; i < t.stack_count; i++) { 1705ffd83dbSDimitry Andric t.stacks[i].idx = i; 1715ffd83dbSDimitry Andric __tsan_get_report_stack(t.report, i, t.stacks[i].trace, REPORT_TRACE_SIZE); 1725ffd83dbSDimitry Andric } 1735ffd83dbSDimitry Andric 1745ffd83dbSDimitry Andric if (t.mop_count > REPORT_ARRAY_SIZE) t.mop_count = REPORT_ARRAY_SIZE; 1755ffd83dbSDimitry Andric for (int i = 0; i < t.mop_count; i++) { 1765ffd83dbSDimitry Andric t.mops[i].idx = i; 1775ffd83dbSDimitry 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); 1785ffd83dbSDimitry Andric } 1795ffd83dbSDimitry Andric 1805ffd83dbSDimitry Andric if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE; 1815ffd83dbSDimitry Andric for (int i = 0; i < t.loc_count; i++) { 1825ffd83dbSDimitry Andric t.locs[i].idx = i; 1835ffd83dbSDimitry 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); 1845ffd83dbSDimitry Andric if (ptr__tsan_get_report_loc_object_type) 1855ffd83dbSDimitry Andric ptr__tsan_get_report_loc_object_type(t.report, i, &t.locs[i].object_type); 1865ffd83dbSDimitry Andric } 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE; 1895ffd83dbSDimitry Andric for (int i = 0; i < t.mutex_count; i++) { 1905ffd83dbSDimitry Andric t.mutexes[i].idx = i; 1915ffd83dbSDimitry 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); 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric 1945ffd83dbSDimitry Andric if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE; 1955ffd83dbSDimitry Andric for (int i = 0; i < t.thread_count; i++) { 1965ffd83dbSDimitry Andric t.threads[i].idx = i; 1975ffd83dbSDimitry 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); 1985ffd83dbSDimitry Andric } 1995ffd83dbSDimitry Andric 2005ffd83dbSDimitry Andric if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE; 2015ffd83dbSDimitry Andric for (int i = 0; i < t.unique_tid_count; i++) { 2025ffd83dbSDimitry Andric t.unique_tids[i].idx = i; 2035ffd83dbSDimitry Andric __tsan_get_report_unique_tid(t.report, i, &t.unique_tids[i].tid); 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric 2065ffd83dbSDimitry Andric t; 2075ffd83dbSDimitry Andric )"; 2085ffd83dbSDimitry Andric 209*bdd1243dSDimitry Andric static StructuredData::ArraySP 2105ffd83dbSDimitry Andric CreateStackTrace(ValueObjectSP o, 2115ffd83dbSDimitry Andric const std::string &trace_item_name = ".trace") { 212*bdd1243dSDimitry Andric auto trace_sp = std::make_shared<StructuredData::Array>(); 2135ffd83dbSDimitry Andric ValueObjectSP trace_value_object = 2145ffd83dbSDimitry Andric o->GetValueForExpressionPath(trace_item_name.c_str()); 2155ffd83dbSDimitry Andric size_t count = trace_value_object->GetNumChildren(); 2165ffd83dbSDimitry Andric for (size_t j = 0; j < count; j++) { 2175ffd83dbSDimitry Andric addr_t trace_addr = 2185ffd83dbSDimitry Andric trace_value_object->GetChildAtIndex(j, true)->GetValueAsUnsigned(0); 2195ffd83dbSDimitry Andric if (trace_addr == 0) 2205ffd83dbSDimitry Andric break; 221*bdd1243dSDimitry Andric trace_sp->AddItem(std::make_shared<StructuredData::Integer>(trace_addr)); 2225ffd83dbSDimitry Andric } 223*bdd1243dSDimitry Andric return trace_sp; 2245ffd83dbSDimitry Andric } 2255ffd83dbSDimitry Andric 226*bdd1243dSDimitry Andric static StructuredData::ArraySP ConvertToStructuredArray( 2275ffd83dbSDimitry Andric ValueObjectSP return_value_sp, const std::string &items_name, 2285ffd83dbSDimitry Andric const std::string &count_name, 229*bdd1243dSDimitry Andric std::function<void(const ValueObjectSP &o, 230*bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict)> const 2315ffd83dbSDimitry Andric &callback) { 232*bdd1243dSDimitry Andric auto array_sp = std::make_shared<StructuredData::Array>(); 2335ffd83dbSDimitry Andric unsigned int count = 2345ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(count_name.c_str()) 2355ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2365ffd83dbSDimitry Andric ValueObjectSP objects = 2375ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(items_name.c_str()); 2385ffd83dbSDimitry Andric for (unsigned int i = 0; i < count; i++) { 2395ffd83dbSDimitry Andric ValueObjectSP o = objects->GetChildAtIndex(i, true); 240*bdd1243dSDimitry Andric auto dict_sp = std::make_shared<StructuredData::Dictionary>(); 2415ffd83dbSDimitry Andric 242*bdd1243dSDimitry Andric callback(o, dict_sp); 2435ffd83dbSDimitry Andric 244*bdd1243dSDimitry Andric array_sp->AddItem(dict_sp); 2455ffd83dbSDimitry Andric } 246*bdd1243dSDimitry Andric return array_sp; 2475ffd83dbSDimitry Andric } 2485ffd83dbSDimitry Andric 2495ffd83dbSDimitry Andric static std::string RetrieveString(ValueObjectSP return_value_sp, 2505ffd83dbSDimitry Andric ProcessSP process_sp, 2515ffd83dbSDimitry Andric const std::string &expression_path) { 2525ffd83dbSDimitry Andric addr_t ptr = 2535ffd83dbSDimitry Andric return_value_sp->GetValueForExpressionPath(expression_path.c_str()) 2545ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 2555ffd83dbSDimitry Andric std::string str; 2565ffd83dbSDimitry Andric Status error; 2575ffd83dbSDimitry Andric process_sp->ReadCStringFromMemory(ptr, str, error); 2585ffd83dbSDimitry Andric return str; 2595ffd83dbSDimitry Andric } 2605ffd83dbSDimitry Andric 2615ffd83dbSDimitry Andric static void 2625ffd83dbSDimitry Andric GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, 2635ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2645ffd83dbSDimitry Andric ConvertToStructuredArray( 2655ffd83dbSDimitry Andric data, ".threads", ".thread_count", 266*bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 267*bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 2685ffd83dbSDimitry Andric uint64_t thread_id = 2695ffd83dbSDimitry Andric o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0); 2705ffd83dbSDimitry Andric uint64_t thread_os_id = 2715ffd83dbSDimitry Andric o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0); 2725ffd83dbSDimitry Andric user_id_t lldb_user_id = 0; 2735ffd83dbSDimitry Andric 2745ffd83dbSDimitry Andric bool can_update = true; 2755ffd83dbSDimitry Andric ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID( 2765ffd83dbSDimitry Andric thread_os_id, can_update); 2775ffd83dbSDimitry Andric if (lldb_thread) { 2785ffd83dbSDimitry Andric lldb_user_id = lldb_thread->GetIndexID(); 2795ffd83dbSDimitry Andric } else { 2805ffd83dbSDimitry Andric // This isn't a live thread anymore. Ask process to assign a new 2815ffd83dbSDimitry Andric // Index ID (or return an old one if we've already seen this 2825ffd83dbSDimitry Andric // thread_os_id). It will also make sure that no new threads are 2835ffd83dbSDimitry Andric // assigned this Index ID. 2845ffd83dbSDimitry Andric lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id); 2855ffd83dbSDimitry Andric } 2865ffd83dbSDimitry Andric 2875ffd83dbSDimitry Andric thread_id_map[thread_id] = lldb_user_id; 2885ffd83dbSDimitry Andric }); 2895ffd83dbSDimitry Andric } 2905ffd83dbSDimitry Andric 2915ffd83dbSDimitry Andric static user_id_t Renumber(uint64_t id, 2925ffd83dbSDimitry Andric std::map<uint64_t, user_id_t> &thread_id_map) { 2935ffd83dbSDimitry Andric auto IT = thread_id_map.find(id); 2945ffd83dbSDimitry Andric if (IT == thread_id_map.end()) 2955ffd83dbSDimitry Andric return 0; 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric return IT->second; 2985ffd83dbSDimitry Andric } 2995ffd83dbSDimitry Andric 3005ffd83dbSDimitry Andric StructuredData::ObjectSP InstrumentationRuntimeTSan::RetrieveReportData( 3015ffd83dbSDimitry Andric ExecutionContextRef exe_ctx_ref) { 3025ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 3035ffd83dbSDimitry Andric if (!process_sp) 3045ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 3055ffd83dbSDimitry Andric 3065ffd83dbSDimitry Andric ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); 3075ffd83dbSDimitry Andric StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); 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 341*bdd1243dSDimitry 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)); 348*bdd1243dSDimitry Andric dict->AddItem("sleep_trace", CreateStackTrace( 349*bdd1243dSDimitry Andric main_value, ".sleep_trace")); 3505ffd83dbSDimitry Andric 351*bdd1243dSDimitry Andric StructuredData::ArraySP stacks = ConvertToStructuredArray( 3525ffd83dbSDimitry Andric main_value, ".stacks", ".stack_count", 353*bdd1243dSDimitry Andric [thread_sp](const ValueObjectSP &o, 354*bdd1243dSDimitry Andric const StructuredData::DictionarySP &dict) { 3555ffd83dbSDimitry Andric dict->AddIntegerItem( 3565ffd83dbSDimitry Andric "index", 3575ffd83dbSDimitry Andric o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0)); 358*bdd1243dSDimitry 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 }); 362*bdd1243dSDimitry Andric dict->AddItem("stacks", stacks); 3635ffd83dbSDimitry Andric 364*bdd1243dSDimitry Andric StructuredData::ArraySP mops = ConvertToStructuredArray( 3655ffd83dbSDimitry Andric main_value, ".mops", ".mop_count", 366*bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 367*bdd1243dSDimitry 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)); 388*bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 3895ffd83dbSDimitry Andric }); 390*bdd1243dSDimitry Andric dict->AddItem("mops", mops); 3915ffd83dbSDimitry Andric 392*bdd1243dSDimitry Andric StructuredData::ArraySP locs = ConvertToStructuredArray( 3935ffd83dbSDimitry Andric main_value, ".locs", ".loc_count", 394*bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 395*bdd1243dSDimitry 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)); 420*bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4215ffd83dbSDimitry Andric dict->AddStringItem("object_type", 4225ffd83dbSDimitry Andric RetrieveString(o, process_sp, ".object_type")); 4235ffd83dbSDimitry Andric }); 424*bdd1243dSDimitry Andric dict->AddItem("locs", locs); 4255ffd83dbSDimitry Andric 426*bdd1243dSDimitry Andric StructuredData::ArraySP mutexes = ConvertToStructuredArray( 4275ffd83dbSDimitry Andric main_value, ".mutexes", ".mutex_count", 428*bdd1243dSDimitry 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)); 441*bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4425ffd83dbSDimitry Andric }); 443*bdd1243dSDimitry Andric dict->AddItem("mutexes", mutexes); 4445ffd83dbSDimitry Andric 445*bdd1243dSDimitry Andric StructuredData::ArraySP threads = ConvertToStructuredArray( 4465ffd83dbSDimitry Andric main_value, ".threads", ".thread_count", 447*bdd1243dSDimitry Andric [process_sp, &thread_id_map](const ValueObjectSP &o, 448*bdd1243dSDimitry 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)); 469*bdd1243dSDimitry Andric dict->AddItem("trace", CreateStackTrace(o)); 4705ffd83dbSDimitry Andric }); 471*bdd1243dSDimitry Andric dict->AddItem("threads", threads); 4725ffd83dbSDimitry Andric 473*bdd1243dSDimitry Andric StructuredData::ArraySP unique_tids = ConvertToStructuredArray( 4745ffd83dbSDimitry Andric main_value, ".unique_tids", ".unique_tid_count", 475*bdd1243dSDimitry Andric [&thread_id_map](const ValueObjectSP &o, 476*bdd1243dSDimitry 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 }); 486*bdd1243dSDimitry Andric dict->AddItem("unique_tids", unique_tids); 4875ffd83dbSDimitry Andric 488*bdd1243dSDimitry 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 5955ffd83dbSDimitry Andric addr_t addr; 5965ffd83dbSDimitry Andric if (!trace_array->GetItemAtIndexAsInteger(i, addr)) 5975ffd83dbSDimitry Andric continue; 5985ffd83dbSDimitry Andric 5995ffd83dbSDimitry Andric lldb_private::Address so_addr; 6005ffd83dbSDimitry Andric if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( 6015ffd83dbSDimitry Andric addr, so_addr)) 6025ffd83dbSDimitry Andric continue; 6035ffd83dbSDimitry Andric 6045ffd83dbSDimitry Andric if (so_addr.GetModule() == runtime_module_sp) 6055ffd83dbSDimitry Andric continue; 6065ffd83dbSDimitry Andric 6075ffd83dbSDimitry Andric return addr; 6085ffd83dbSDimitry Andric } 6095ffd83dbSDimitry Andric 6105ffd83dbSDimitry Andric return 0; 6115ffd83dbSDimitry Andric } 6125ffd83dbSDimitry Andric 6135ffd83dbSDimitry Andric std::string 6145ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GenerateSummary(StructuredData::ObjectSP report) { 6155ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 6165ffd83dbSDimitry Andric 6175ffd83dbSDimitry Andric std::string summary = std::string(report->GetAsDictionary() 6185ffd83dbSDimitry Andric ->GetValueForKey("description") 6195ffd83dbSDimitry Andric ->GetAsString() 6205ffd83dbSDimitry Andric ->GetValue()); 6215ffd83dbSDimitry Andric bool skip_one_frame = 6225ffd83dbSDimitry Andric report->GetObjectForDotSeparatedPath("issue_type")->GetStringValue() == 6235ffd83dbSDimitry Andric "external-race"; 6245ffd83dbSDimitry Andric 6255ffd83dbSDimitry Andric addr_t pc = 0; 6265ffd83dbSDimitry Andric if (report->GetAsDictionary() 6275ffd83dbSDimitry Andric ->GetValueForKey("mops") 6285ffd83dbSDimitry Andric ->GetAsArray() 6295ffd83dbSDimitry Andric ->GetSize() > 0) 6305ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6315ffd83dbSDimitry Andric ->GetValueForKey("mops") 6325ffd83dbSDimitry Andric ->GetAsArray() 6335ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6345ffd83dbSDimitry Andric ->GetAsDictionary() 6355ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6365ffd83dbSDimitry Andric skip_one_frame); 6375ffd83dbSDimitry Andric 6385ffd83dbSDimitry Andric if (report->GetAsDictionary() 6395ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6405ffd83dbSDimitry Andric ->GetAsArray() 6415ffd83dbSDimitry Andric ->GetSize() > 0) 6425ffd83dbSDimitry Andric pc = GetFirstNonInternalFramePc(report->GetAsDictionary() 6435ffd83dbSDimitry Andric ->GetValueForKey("stacks") 6445ffd83dbSDimitry Andric ->GetAsArray() 6455ffd83dbSDimitry Andric ->GetItemAtIndex(0) 6465ffd83dbSDimitry Andric ->GetAsDictionary() 6475ffd83dbSDimitry Andric ->GetValueForKey("trace"), 6485ffd83dbSDimitry Andric skip_one_frame); 6495ffd83dbSDimitry Andric 6505ffd83dbSDimitry Andric if (pc != 0) { 6515ffd83dbSDimitry Andric summary = summary + " in " + GetSymbolNameFromAddress(process_sp, pc); 6525ffd83dbSDimitry Andric } 6535ffd83dbSDimitry Andric 6545ffd83dbSDimitry Andric if (report->GetAsDictionary() 6555ffd83dbSDimitry Andric ->GetValueForKey("locs") 6565ffd83dbSDimitry Andric ->GetAsArray() 6575ffd83dbSDimitry Andric ->GetSize() > 0) { 6585ffd83dbSDimitry Andric StructuredData::ObjectSP loc = report->GetAsDictionary() 6595ffd83dbSDimitry Andric ->GetValueForKey("locs") 6605ffd83dbSDimitry Andric ->GetAsArray() 6615ffd83dbSDimitry Andric ->GetItemAtIndex(0); 6625ffd83dbSDimitry Andric std::string object_type = std::string(loc->GetAsDictionary() 6635ffd83dbSDimitry Andric ->GetValueForKey("object_type") 6645ffd83dbSDimitry Andric ->GetAsString() 6655ffd83dbSDimitry Andric ->GetValue()); 6665ffd83dbSDimitry Andric if (!object_type.empty()) { 6675ffd83dbSDimitry Andric summary = "Race on " + object_type + " object"; 6685ffd83dbSDimitry Andric } 6695ffd83dbSDimitry Andric addr_t addr = loc->GetAsDictionary() 6705ffd83dbSDimitry Andric ->GetValueForKey("address") 6715ffd83dbSDimitry Andric ->GetAsInteger() 6725ffd83dbSDimitry Andric ->GetValue(); 6735ffd83dbSDimitry Andric if (addr == 0) 6745ffd83dbSDimitry Andric addr = loc->GetAsDictionary() 6755ffd83dbSDimitry Andric ->GetValueForKey("start") 6765ffd83dbSDimitry Andric ->GetAsInteger() 6775ffd83dbSDimitry Andric ->GetValue(); 6785ffd83dbSDimitry Andric 6795ffd83dbSDimitry Andric if (addr != 0) { 6805ffd83dbSDimitry Andric std::string global_name = GetSymbolNameFromAddress(process_sp, addr); 6815ffd83dbSDimitry Andric if (!global_name.empty()) { 6825ffd83dbSDimitry Andric summary = summary + " at " + global_name; 6835ffd83dbSDimitry Andric } else { 6845ffd83dbSDimitry Andric summary = summary + " at " + Sprintf("0x%llx", addr); 6855ffd83dbSDimitry Andric } 6865ffd83dbSDimitry Andric } else { 6875ffd83dbSDimitry Andric int fd = loc->GetAsDictionary() 6885ffd83dbSDimitry Andric ->GetValueForKey("file_descriptor") 6895ffd83dbSDimitry Andric ->GetAsInteger() 6905ffd83dbSDimitry Andric ->GetValue(); 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 { 7065ffd83dbSDimitry Andric addr_t addr = 7075ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("address")->GetIntegerValue(); 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") 7365ffd83dbSDimitry Andric ->GetAsInteger() 7375ffd83dbSDimitry Andric ->GetValue(); 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") 7555ffd83dbSDimitry Andric ->GetAsInteger() 7565ffd83dbSDimitry Andric ->GetValue(); 7575ffd83dbSDimitry Andric long size = loc->GetAsDictionary() 7585ffd83dbSDimitry Andric ->GetValueForKey("size") 7595ffd83dbSDimitry Andric ->GetAsInteger() 7605ffd83dbSDimitry Andric ->GetValue(); 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") { 7735ffd83dbSDimitry Andric int tid = loc->GetAsDictionary() 7745ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 7755ffd83dbSDimitry Andric ->GetAsInteger() 7765ffd83dbSDimitry Andric ->GetValue(); 7775ffd83dbSDimitry Andric result = Sprintf("Location is stack of thread %d", tid); 7785ffd83dbSDimitry Andric } else if (type == "tls") { 7795ffd83dbSDimitry Andric int tid = loc->GetAsDictionary() 7805ffd83dbSDimitry Andric ->GetValueForKey("thread_id") 7815ffd83dbSDimitry Andric ->GetAsInteger() 7825ffd83dbSDimitry Andric ->GetValue(); 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") 7875ffd83dbSDimitry Andric ->GetAsInteger() 7885ffd83dbSDimitry Andric ->GetValue(); 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 { 8515ffd83dbSDimitry Andric addr_t addr = 8525ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("address")->GetIntegerValue(); 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 918*bdd1243dSDimitry Andric const bool internal = true; 919*bdd1243dSDimitry Andric const bool hardware = false; 920*bdd1243dSDimitry 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, 926*bdd1243dSDimitry 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") { 9495ffd83dbSDimitry Andric int size = o->GetObjectForDotSeparatedPath("size")->GetIntegerValue(); 9505ffd83dbSDimitry Andric int thread_id = 9515ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue(); 9525ffd83dbSDimitry Andric bool is_write = 9535ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue(); 9545ffd83dbSDimitry Andric bool is_atomic = 9555ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("is_atomic")->GetBooleanValue(); 9565ffd83dbSDimitry Andric addr_t addr = o->GetObjectForDotSeparatedPath("address")->GetIntegerValue(); 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 { 9735ffd83dbSDimitry Andric result = Sprintf("%s%s of size %d%s by thread %d", 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") { 9805ffd83dbSDimitry Andric int thread_id = 9815ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue(); 9825ffd83dbSDimitry Andric result = Sprintf("Thread %d 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()); 9885ffd83dbSDimitry Andric int thread_id = 9895ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue(); 9905ffd83dbSDimitry Andric int fd = 9915ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("file_descriptor")->GetIntegerValue(); 9925ffd83dbSDimitry Andric if (type == "heap") { 9935ffd83dbSDimitry Andric result = Sprintf("Heap block allocated by thread %d", thread_id); 9945ffd83dbSDimitry Andric } else if (type == "fd") { 9955ffd83dbSDimitry Andric result = 9965ffd83dbSDimitry Andric Sprintf("File descriptor %d created by thread %t", fd, thread_id); 9975ffd83dbSDimitry Andric } 9985ffd83dbSDimitry Andric } 9995ffd83dbSDimitry Andric 10005ffd83dbSDimitry Andric if (path == "mutexes") { 10015ffd83dbSDimitry Andric int mutex_id = 10025ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("mutex_id")->GetIntegerValue(); 10035ffd83dbSDimitry Andric 10045ffd83dbSDimitry Andric result = Sprintf("Mutex M%d created", mutex_id); 10055ffd83dbSDimitry Andric } 10065ffd83dbSDimitry Andric 10075ffd83dbSDimitry Andric if (path == "stacks") { 10085ffd83dbSDimitry Andric int thread_id = 10095ffd83dbSDimitry Andric o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue(); 10105ffd83dbSDimitry Andric result = Sprintf("Thread %d", 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 { 10265ffd83dbSDimitry Andric pcs.push_back(pc->GetAsInteger()->GetValue()); 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"); 10355ffd83dbSDimitry Andric tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; 10365ffd83dbSDimitry Andric 1037*bdd1243dSDimitry Andric ThreadSP new_thread_sp = 1038*bdd1243dSDimitry Andric std::make_shared<HistoryThread>(*process_sp, tid, pcs); 10395ffd83dbSDimitry Andric new_thread_sp->SetName(GenerateThreadName(path, o, info).c_str()); 10405ffd83dbSDimitry Andric 10415ffd83dbSDimitry Andric // Save this in the Process' ExtendedThreadList so a strong pointer 10425ffd83dbSDimitry Andric // retains the object 10435ffd83dbSDimitry Andric process_sp->GetExtendedThreadList().AddThread(new_thread_sp); 10445ffd83dbSDimitry Andric threads->AddThread(new_thread_sp); 10455ffd83dbSDimitry Andric 10465ffd83dbSDimitry Andric return true; 10475ffd83dbSDimitry Andric }); 10485ffd83dbSDimitry Andric } 10495ffd83dbSDimitry Andric 10505ffd83dbSDimitry Andric lldb::ThreadCollectionSP 10515ffd83dbSDimitry Andric InstrumentationRuntimeTSan::GetBacktracesFromExtendedStopInfo( 10525ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 1053*bdd1243dSDimitry Andric 1054*bdd1243dSDimitry Andric ThreadCollectionSP threads = std::make_shared<ThreadCollection>(); 10555ffd83dbSDimitry Andric 10565ffd83dbSDimitry Andric if (info->GetObjectForDotSeparatedPath("instrumentation_class") 10575ffd83dbSDimitry Andric ->GetStringValue() != "ThreadSanitizer") 10585ffd83dbSDimitry Andric return threads; 10595ffd83dbSDimitry Andric 10605ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 10615ffd83dbSDimitry Andric 10625ffd83dbSDimitry Andric AddThreadsForPath("stacks", threads, process_sp, info); 10635ffd83dbSDimitry Andric AddThreadsForPath("mops", threads, process_sp, info); 10645ffd83dbSDimitry Andric AddThreadsForPath("locs", threads, process_sp, info); 10655ffd83dbSDimitry Andric AddThreadsForPath("mutexes", threads, process_sp, info); 10665ffd83dbSDimitry Andric AddThreadsForPath("threads", threads, process_sp, info); 10675ffd83dbSDimitry Andric 10685ffd83dbSDimitry Andric return threads; 10695ffd83dbSDimitry Andric } 1070