40 lldb::InstrumentationRuntimeSP
41 InstrumentationRuntimeTSan::CreateInstance(
const lldb::ProcessSP &process_sp) {
45 void InstrumentationRuntimeTSan::Initialize() {
46 PluginManager::RegisterPlugin(
47 GetPluginNameStatic(),
"ThreadSanitizer instrumentation runtime plugin.",
48 CreateInstance, GetTypeStatic);
51 void InstrumentationRuntimeTSan::Terminate() {
52 PluginManager::UnregisterPlugin(CreateInstance);
59 InstrumentationRuntimeTSan::~InstrumentationRuntimeTSan() { Deactivate(); }
64 void *__tsan_get_current_report();
65 int __tsan_get_report_data(void *report, const char **description, int *count,
66 int *stack_count, int *mop_count, int *loc_count,
67 int *mutex_count, int *thread_count,
68 int *unique_tid_count, void **sleep_trace,
69 unsigned long trace_size);
70 int __tsan_get_report_stack(void *report, unsigned long idx, void **trace,
71 unsigned long trace_size);
72 int __tsan_get_report_mop(void *report, unsigned long idx, int *tid, void **addr,
73 int *size, int *write, int *atomic, void **trace,
74 unsigned long trace_size);
75 int __tsan_get_report_loc(void *report, unsigned long idx, const char **type,
76 void **addr, unsigned long *start, unsigned long *size, int *tid,
77 int *fd, int *suppressable, void **trace,
78 unsigned long trace_size);
79 int __tsan_get_report_mutex(void *report, unsigned long idx, unsigned long *mutex_id, void **addr,
80 int *destroyed, void **trace, unsigned long trace_size);
81 int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *os_id,
82 int *running, const char **name, int *parent_tid,
83 void **trace, unsigned long trace_size);
84 int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid);
86 // TODO: dlsym won't work on Windows.
87 void *dlsym(void* handle, const char* symbol);
88 int (*ptr__tsan_get_report_loc_object_type)(void *report, unsigned long idx, const char **object_type);
91 const int REPORT_TRACE_SIZE = 128;
92 const int REPORT_ARRAY_SIZE = 4;
96 const char *description;
99 void *sleep_trace[REPORT_TRACE_SIZE];
104 void *trace[REPORT_TRACE_SIZE];
105 } stacks[REPORT_ARRAY_SIZE];
115 void *trace[REPORT_TRACE_SIZE];
116 } mops[REPORT_ARRAY_SIZE];
128 void *trace[REPORT_TRACE_SIZE];
129 const char *object_type;
130 } locs[REPORT_ARRAY_SIZE];
135 unsigned long mutex_id;
138 void *trace[REPORT_TRACE_SIZE];
139 } mutexes[REPORT_ARRAY_SIZE];
149 void *trace[REPORT_TRACE_SIZE];
150 } threads[REPORT_ARRAY_SIZE];
152 int unique_tid_count;
156 } unique_tids[REPORT_ARRAY_SIZE];
163 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");
165 t.report = __tsan_get_current_report();
166 __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);
168 if (t.stack_count > REPORT_ARRAY_SIZE) t.stack_count = REPORT_ARRAY_SIZE;
169 for (int i = 0; i < t.stack_count; i++) {
171 __tsan_get_report_stack(t.report, i, t.stacks[i].trace, REPORT_TRACE_SIZE);
174 if (t.mop_count > REPORT_ARRAY_SIZE) t.mop_count = REPORT_ARRAY_SIZE;
175 for (int i = 0; i < t.mop_count; i++) {
177 __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);
180 if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE;
181 for (int i = 0; i < t.loc_count; i++) {
183 __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);
184 if (ptr__tsan_get_report_loc_object_type)
185 ptr__tsan_get_report_loc_object_type(t.report, i, &t.locs[i].object_type);
188 if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE;
189 for (int i = 0; i < t.mutex_count; i++) {
190 t.mutexes[i].idx = i;
191 __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);
194 if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE;
195 for (int i = 0; i < t.thread_count; i++) {
196 t.threads[i].idx = i;
197 __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);
200 if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE;
201 for (int i = 0; i < t.unique_tid_count; i++) {
202 t.unique_tids[i].idx = i;
203 __tsan_get_report_unique_tid(t.report, i, &t.unique_tids[i].tid);
213 ValueObjectSP trace_value_object =
214 o->GetValueForExpressionPath(trace_item_name.c_str());
215 size_t count = trace_value_object->GetNumChildren();
216 for (
size_t j = 0; j < count; j++) {
218 trace_value_object->GetChildAtIndex(j,
true)->GetValueAsUnsigned(0);
228 ValueObjectSP return_value_sp,
const std::string &items_name,
234 return_value_sp->GetValueForExpressionPath(count_name.c_str())
235 ->GetValueAsUnsigned(0);
236 ValueObjectSP objects =
237 return_value_sp->GetValueForExpressionPath(items_name.c_str());
238 for (
unsigned int i = 0; i < count; i++) {
239 ValueObjectSP o = objects->GetChildAtIndex(i,
true);
250 ProcessSP process_sp,
253 return_value_sp->GetValueForExpressionPath(expression_path.c_str())
254 ->GetValueAsUnsigned(0);
257 process_sp->ReadCStringFromMemory(ptr, str,
error);
263 std::map<uint64_t, user_id_t> &thread_id_map) {
265 data,
".threads",
".thread_count",
266 [process_sp, &thread_id_map](ValueObjectSP o,
269 o->GetValueForExpressionPath(
".tid")->GetValueAsUnsigned(0);
270 uint64_t thread_os_id =
271 o->GetValueForExpressionPath(
".os_id")->GetValueAsUnsigned(0);
274 bool can_update =
true;
275 ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID(
276 thread_os_id, can_update);
278 lldb_user_id = lldb_thread->GetIndexID();
284 lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id);
287 thread_id_map[thread_id] = lldb_user_id;
292 std::map<uint64_t, user_id_t> &thread_id_map) {
293 auto IT = thread_id_map.find(
id);
294 if (IT == thread_id_map.end())
302 ProcessSP process_sp = GetProcessSP();
307 StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
317 options.
SetTimeout(process_sp->GetUtilityExpressionTimeout());
322 ValueObjectSP main_value;
325 frame_sp->CalculateExecutionContext(exe_ctx);
328 main_value, eval_error);
331 ss <<
"cannot evaluate ThreadSanitizer expression:\n";
333 Debugger::ReportWarning(ss.
GetString().str(),
334 process_sp->GetTarget().GetDebugger().GetID());
338 std::map<uint64_t, user_id_t> thread_id_map;
342 dict->
AddStringItem(
"instrumentation_class",
"ThreadSanitizer");
346 main_value->GetValueForExpressionPath(
".report_count")
347 ->GetValueAsUnsigned(0));
349 main_value,
".sleep_trace")));
352 main_value,
".stacks",
".stack_count",
356 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
364 main_value,
".mops",
".mop_count",
368 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
372 o->GetValueForExpressionPath(
".tid")->GetValueAsUnsigned(0),
376 o->GetValueForExpressionPath(
".size")->GetValueAsUnsigned(0));
379 o->GetValueForExpressionPath(
".write")->GetValueAsUnsigned(0));
382 o->GetValueForExpressionPath(
".atomic")->GetValueAsUnsigned(0));
385 o->GetValueForExpressionPath(
".addr")->GetValueAsUnsigned(0));
391 main_value,
".locs",
".loc_count",
392 [process_sp, &thread_id_map](ValueObjectSP o,
396 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
400 o->GetValueForExpressionPath(
".addr")->GetValueAsUnsigned(0));
403 o->GetValueForExpressionPath(
".start")->GetValueAsUnsigned(0));
406 o->GetValueForExpressionPath(
".size")->GetValueAsUnsigned(0));
410 o->GetValueForExpressionPath(
".tid")->GetValueAsUnsigned(0),
414 o->GetValueForExpressionPath(
".fd")->GetValueAsUnsigned(0));
416 o->GetValueForExpressionPath(
".suppressable")
417 ->GetValueAsUnsigned(0));
425 main_value,
".mutexes",
".mutex_count",
429 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
432 o->GetValueForExpressionPath(
".mutex_id")->GetValueAsUnsigned(0));
435 o->GetValueForExpressionPath(
".addr")->GetValueAsUnsigned(0));
438 o->GetValueForExpressionPath(
".destroyed")->GetValueAsUnsigned(0));
444 main_value,
".threads",
".thread_count",
445 [process_sp, &thread_id_map](ValueObjectSP o,
449 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
453 o->GetValueForExpressionPath(
".tid")->GetValueAsUnsigned(0),
457 o->GetValueForExpressionPath(
".os_id")->GetValueAsUnsigned(0));
460 o->GetValueForExpressionPath(
".running")->GetValueAsUnsigned(0));
464 Renumber(o->GetValueForExpressionPath(
".parent_tid")
465 ->GetValueAsUnsigned(0),
472 main_value,
".unique_tids",
".unique_tid_count",
476 o->GetValueForExpressionPath(
".idx")->GetValueAsUnsigned(0));
480 o->GetValueForExpressionPath(
".tid")->GetValueAsUnsigned(0),
491 ->GetValueForKey(
"issue_type")
495 if (description ==
"data-race") {
497 }
else if (description ==
"data-race-vptr") {
498 return "Data race on C++ virtual pointer";
499 }
else if (description ==
"heap-use-after-free") {
500 return "Use of deallocated memory";
501 }
else if (description ==
"heap-use-after-free-vptr") {
502 return "Use of deallocated C++ virtual pointer";
503 }
else if (description ==
"thread-leak") {
504 return "Thread leak";
505 }
else if (description ==
"locked-mutex-destroy") {
506 return "Destruction of a locked mutex";
507 }
else if (description ==
"mutex-double-lock") {
508 return "Double lock of a mutex";
509 }
else if (description ==
"mutex-invalid-access") {
510 return "Use of an uninitialized or destroyed mutex";
511 }
else if (description ==
"mutex-bad-unlock") {
512 return "Unlock of an unlocked mutex (or by a wrong thread)";
513 }
else if (description ==
"mutex-bad-read-lock") {
514 return "Read lock of a write locked mutex";
515 }
else if (description ==
"mutex-bad-read-unlock") {
516 return "Read unlock of a write locked mutex";
517 }
else if (description ==
"signal-unsafe-call") {
518 return "Signal-unsafe call inside a signal handler";
519 }
else if (description ==
"errno-in-signal-handler") {
520 return "Overwrite of errno in a signal handler";
521 }
else if (description ==
"lock-order-inversion") {
522 return "Lock order inversion (potential deadlock)";
523 }
else if (description ==
"external-race") {
524 return "Race on a library object";
525 }
else if (description ==
"swift-access-race") {
526 return "Swift access race";
536 va_start(args, format);
544 if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr,
559 if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr,
579 decl = var->GetDeclaration();
582 addr_t InstrumentationRuntimeTSan::GetFirstNonInternalFramePc(
584 ProcessSP process_sp = GetProcessSP();
585 ModuleSP runtime_module_sp = GetRuntimeModuleSP();
588 for (
size_t i = 0; i < trace_array->
GetSize(); i++) {
589 if (skip_one_frame && i == 0)
597 if (!process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(
601 if (so_addr.
GetModule() == runtime_module_sp)
612 ProcessSP process_sp = GetProcessSP();
615 ->GetValueForKey(
"description")
618 bool skip_one_frame =
619 report->GetObjectForDotSeparatedPath(
"issue_type")->GetStringValue() ==
623 if (report->GetAsDictionary()
624 ->GetValueForKey(
"mops")
627 pc = GetFirstNonInternalFramePc(report->GetAsDictionary()
628 ->GetValueForKey(
"mops")
632 ->GetValueForKey(
"trace"),
635 if (report->GetAsDictionary()
636 ->GetValueForKey(
"stacks")
639 pc = GetFirstNonInternalFramePc(report->GetAsDictionary()
640 ->GetValueForKey(
"stacks")
644 ->GetValueForKey(
"trace"),
651 if (report->GetAsDictionary()
652 ->GetValueForKey(
"locs")
656 ->GetValueForKey(
"locs")
660 ->GetValueForKey(
"object_type")
663 if (!object_type.empty()) {
664 summary =
"Race on " + object_type +
" object";
666 addr_t addr = loc->GetAsDictionary()
667 ->GetValueForKey(
"address")
671 addr = loc->GetAsDictionary()
672 ->GetValueForKey(
"start")
678 if (!global_name.empty()) {
679 summary = summary +
" at " + global_name;
681 summary = summary +
" at " +
Sprintf(
"0x%llx", addr);
684 int fd = loc->GetAsDictionary()
685 ->GetValueForKey(
"file_descriptor")
689 summary = summary +
" on file descriptor " +
Sprintf(
"%d", fd);
697 addr_t InstrumentationRuntimeTSan::GetMainRacyAddress(
701 report->GetObjectForDotSeparatedPath(
"mops")->GetAsArray()->ForEach(
710 return (result == (
addr_t)-1) ? 0 : result;
718 ProcessSP process_sp = GetProcessSP();
720 if (report->GetAsDictionary()
721 ->GetValueForKey(
"locs")
725 ->GetValueForKey(
"locs")
729 loc->GetAsDictionary()->GetValueForKey(
"type")->GetStringValue());
730 if (type ==
"global") {
731 global_addr = loc->GetAsDictionary()
732 ->GetValueForKey(
"address")
736 if (!global_name.empty()) {
737 result =
Sprintf(
"'%s' is a global variable (0x%llx)",
738 global_name.c_str(), global_addr);
740 result =
Sprintf(
"0x%llx is a global variable", global_addr);
749 }
else if (type ==
"heap") {
750 addr_t addr = loc->GetAsDictionary()
751 ->GetValueForKey(
"start")
754 long size = loc->GetAsDictionary()
755 ->GetValueForKey(
"size")
759 ->GetValueForKey(
"object_type")
762 if (!object_type.empty()) {
763 result =
Sprintf(
"Location is a %ld-byte %s object at 0x%llx", size,
764 object_type.c_str(), addr);
767 Sprintf(
"Location is a %ld-byte heap object at 0x%llx", size, addr);
769 }
else if (type ==
"stack") {
770 int tid = loc->GetAsDictionary()
771 ->GetValueForKey(
"thread_id")
774 result =
Sprintf(
"Location is stack of thread %d", tid);
775 }
else if (type ==
"tls") {
776 int tid = loc->GetAsDictionary()
777 ->GetValueForKey(
"thread_id")
780 result =
Sprintf(
"Location is TLS of thread %d", tid);
781 }
else if (type ==
"fd") {
782 int fd = loc->GetAsDictionary()
783 ->GetValueForKey(
"file_descriptor")
786 result =
Sprintf(
"Location is file descriptor %d", fd);
793 bool InstrumentationRuntimeTSan::NotifyBreakpointHit(
796 assert(baton &&
"null baton");
805 if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
811 "unknown thread sanitizer fault (unable to extract thread sanitizer "
815 report->GetAsDictionary()->AddStringItem(
"description", issue_description);
816 stop_reason_description = issue_description +
" detected";
817 report->GetAsDictionary()->AddStringItem(
"stop_description",
818 stop_reason_description);
820 report->GetAsDictionary()->AddStringItem(
"summary", summary);
822 report->GetAsDictionary()->AddIntegerItem(
"memory_address", main_address);
829 report, global_addr, global_name, location_filename, location_line);
830 report->GetAsDictionary()->AddStringItem(
"location_description",
831 location_description);
832 if (global_addr != 0) {
833 report->GetAsDictionary()->AddIntegerItem(
"global_address", global_addr);
835 if (!global_name.empty()) {
836 report->GetAsDictionary()->AddStringItem(
"global_name", global_name);
838 if (location_filename !=
"") {
839 report->GetAsDictionary()->AddStringItem(
"location_filename",
841 report->GetAsDictionary()->AddIntegerItem(
"location_line", location_line);
844 bool all_addresses_are_same =
true;
845 report->GetObjectForDotSeparatedPath(
"mops")->GetAsArray()->ForEach(
846 [&all_addresses_are_same,
850 if (main_address != addr)
851 all_addresses_are_same =
false;
854 report->GetAsDictionary()->AddBooleanItem(
"all_addresses_are_same",
855 all_addresses_are_same);
862 thread_sp->SetStopInfo(
864 CreateStopReasonWithInstrumentationData(
865 *thread_sp, stop_reason_description, report));
867 StreamFile &s = process_sp->GetTarget().GetDebugger().GetOutputStream();
868 s.
Printf(
"ThreadSanitizer report breakpoint hit. Use 'thread "
869 "info -s' to get extended information about the "
878 InstrumentationRuntimeTSan::GetPatternForRuntimeLibrary() {
883 bool InstrumentationRuntimeTSan::CheckIfRuntimeIsValid(
884 const lldb::ModuleSP module_sp) {
885 static ConstString g_tsan_get_current_report(
"__tsan_get_current_report");
886 const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
888 return symbol !=
nullptr;
891 void InstrumentationRuntimeTSan::Activate() {
895 ProcessSP process_sp = GetProcessSP();
900 const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType(
903 if (symbol ==
nullptr)
909 Target &target = process_sp->GetTarget();
915 bool internal =
true;
916 bool hardware =
false;
921 breakpoint->
SetCallback(InstrumentationRuntimeTSan::NotifyBreakpointHit,
this,
924 SetBreakpointID(breakpoint->
GetID());
929 void InstrumentationRuntimeTSan::Deactivate() {
931 ProcessSP process_sp = GetProcessSP();
933 process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
944 if (path ==
"mops") {
956 if (main_info->GetObjectForDotSeparatedPath(
"all_addresses_are_same")
957 ->GetBooleanValue()) {
961 if (main_info->GetObjectForDotSeparatedPath(
"issue_type")
962 ->GetStringValue() ==
"external-race") {
963 result =
Sprintf(
"%s access by thread %d",
964 is_write ?
"mutating" :
"read-only", thread_id);
965 }
else if (main_info->GetObjectForDotSeparatedPath(
"issue_type")
966 ->GetStringValue() ==
"swift-access-race") {
967 result =
Sprintf(
"modifying access by thread %d", thread_id);
969 result =
Sprintf(
"%s%s of size %d%s by thread %d",
970 is_atomic ?
"atomic " :
"", is_write ?
"write" :
"read",
971 size, addr_string.c_str(), thread_id);
975 if (path ==
"threads") {
978 result =
Sprintf(
"Thread %d created", thread_id);
981 if (path ==
"locs") {
988 if (type ==
"heap") {
989 result =
Sprintf(
"Heap block allocated by thread %d", thread_id);
990 }
else if (type ==
"fd") {
992 Sprintf(
"File descriptor %d created by thread %t", fd, thread_id);
996 if (path ==
"mutexes") {
1000 result =
Sprintf(
"Mutex M%d created", mutex_id);
1003 if (path ==
"stacks") {
1006 result =
Sprintf(
"Thread %d", thread_id);
1009 result[0] = toupper(result[0]);
1015 ThreadCollectionSP threads, ProcessSP process_sp,
1017 info->GetObjectForDotSeparatedPath(path)->GetAsArray()->ForEach(
1019 std::vector<lldb::addr_t> pcs;
1022 pcs.push_back(
pc->GetAsInteger()->GetValue());
1026 if (pcs.size() == 0)
1031 tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
1035 ThreadSP new_thread_sp(history_thread);
1040 process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
1041 threads->AddThread(new_thread_sp);
1047 lldb::ThreadCollectionSP
1048 InstrumentationRuntimeTSan::GetBacktracesFromExtendedStopInfo(
1050 ThreadCollectionSP threads;
1051 threads = std::make_shared<ThreadCollection>();
1053 if (info->GetObjectForDotSeparatedPath(
"instrumentation_class")
1054 ->GetStringValue() !=
"ThreadSanitizer")
1057 ProcessSP process_sp = GetProcessSP();