]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp
Merge ^/head r307383 through r307735.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / InstrumentationRuntime / ThreadSanitizer / ThreadSanitizerRuntime.cpp
1 //===-- ThreadSanitizerRuntime.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "ThreadSanitizerRuntime.h"
11
12 #include "lldb/Breakpoint/StoppointCallbackContext.h"
13 #include "lldb/Core/Debugger.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Core/ModuleList.h"
16 #include "lldb/Core/RegularExpression.h"
17 #include "lldb/Core/PluginInterface.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Core/Stream.h"
20 #include "lldb/Core/StreamFile.h"
21 #include "lldb/Core/ValueObject.h"
22 #include "lldb/Expression/UserExpression.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Symbol/Symbol.h"
25 #include "lldb/Symbol/SymbolContext.h"
26 #include "lldb/Symbol/Variable.h"
27 #include "lldb/Symbol/VariableList.h"
28 #include "lldb/Target/InstrumentationRuntimeStopInfo.h"
29 #include "lldb/Target/SectionLoadList.h"
30 #include "lldb/Target/StopInfo.h"
31 #include "lldb/Target/Target.h"
32 #include "lldb/Target/Thread.h"
33 #include "Plugins/Process/Utility/HistoryThread.h"
34
35 using namespace lldb;
36 using namespace lldb_private;
37
38 lldb::InstrumentationRuntimeSP
39 ThreadSanitizerRuntime::CreateInstance (const lldb::ProcessSP &process_sp)
40 {
41     return InstrumentationRuntimeSP(new ThreadSanitizerRuntime(process_sp));
42 }
43
44 void
45 ThreadSanitizerRuntime::Initialize()
46 {
47     PluginManager::RegisterPlugin (GetPluginNameStatic(),
48                                    "ThreadSanitizer instrumentation runtime plugin.",
49                                    CreateInstance,
50                                    GetTypeStatic);
51 }
52
53 void
54 ThreadSanitizerRuntime::Terminate()
55 {
56     PluginManager::UnregisterPlugin (CreateInstance);
57 }
58
59 lldb_private::ConstString
60 ThreadSanitizerRuntime::GetPluginNameStatic()
61 {
62     return ConstString("ThreadSanitizer");
63 }
64
65 lldb::InstrumentationRuntimeType
66 ThreadSanitizerRuntime::GetTypeStatic()
67 {
68     return eInstrumentationRuntimeTypeThreadSanitizer;
69 }
70
71 ThreadSanitizerRuntime::ThreadSanitizerRuntime(const ProcessSP &process_sp) :
72 m_is_active(false),
73 m_runtime_module_wp(),
74 m_process_wp(),
75 m_breakpoint_id(0)
76 {
77     if (process_sp)
78         m_process_wp = process_sp;
79 }
80
81 ThreadSanitizerRuntime::~ThreadSanitizerRuntime()
82 {
83     Deactivate();
84 }
85
86 static bool
87 ModuleContainsTSanRuntime(ModuleSP module_sp)
88 {
89     static ConstString g_tsan_get_current_report("__tsan_get_current_report");
90     const Symbol* symbol = module_sp->FindFirstSymbolWithNameAndType(g_tsan_get_current_report, lldb::eSymbolTypeAny);
91     return symbol != nullptr;
92 }
93
94 void
95 ThreadSanitizerRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list)
96 {
97     if (IsActive())
98         return;
99     
100     if (GetRuntimeModuleSP()) {
101         Activate();
102         return;
103     }
104     
105     module_list.ForEach ([this](const lldb::ModuleSP module_sp) -> bool
106     {
107         const FileSpec & file_spec = module_sp->GetFileSpec();
108         if (! file_spec)
109             return true; // Keep iterating through modules
110         
111         llvm::StringRef module_basename(file_spec.GetFilename().GetStringRef());
112         if (module_sp->IsExecutable() || module_basename.startswith("libclang_rt.tsan_"))
113         {
114             if (ModuleContainsTSanRuntime(module_sp))
115             {
116                 m_runtime_module_wp = module_sp;
117                 Activate();
118                 return false; // Stop iterating
119             }
120         }
121
122         return true; // Keep iterating through modules
123     });
124 }
125
126 bool
127 ThreadSanitizerRuntime::IsActive()
128 {
129     return m_is_active;
130 }
131
132 #define RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC 2*1000*1000
133
134 const char *
135 thread_sanitizer_retrieve_report_data_prefix = R"(
136 extern "C"
137 {
138     void *__tsan_get_current_report();
139     int __tsan_get_report_data(void *report, const char **description, int *count,
140                                int *stack_count, int *mop_count, int *loc_count,
141                                int *mutex_count, int *thread_count,
142                                int *unique_tid_count, void **sleep_trace,
143                                unsigned long trace_size);
144     int __tsan_get_report_stack(void *report, unsigned long idx, void **trace,
145                                 unsigned long trace_size);
146     int __tsan_get_report_mop(void *report, unsigned long idx, int *tid, void **addr,
147                               int *size, int *write, int *atomic, void **trace,
148                               unsigned long trace_size);
149     int __tsan_get_report_loc(void *report, unsigned long idx, const char **type,
150                               void **addr, unsigned long *start, unsigned long *size, int *tid,
151                               int *fd, int *suppressable, void **trace,
152                               unsigned long trace_size);
153     int __tsan_get_report_mutex(void *report, unsigned long idx, unsigned long *mutex_id, void **addr,
154                                 int *destroyed, void **trace, unsigned long trace_size);
155     int __tsan_get_report_thread(void *report, unsigned long idx, int *tid, unsigned long *os_id,
156                                  int *running, const char **name, int *parent_tid,
157                                  void **trace, unsigned long trace_size);
158     int __tsan_get_report_unique_tid(void *report, unsigned long idx, int *tid);
159 }
160
161 const int REPORT_TRACE_SIZE = 128;
162 const int REPORT_ARRAY_SIZE = 4;
163
164 struct data {
165     void *report;
166     const char *description;
167     int report_count;
168     
169     void *sleep_trace[REPORT_TRACE_SIZE];
170     
171     int stack_count;
172     struct {
173         int idx;
174         void *trace[REPORT_TRACE_SIZE];
175     } stacks[REPORT_ARRAY_SIZE];
176     
177     int mop_count;
178     struct {
179         int idx;
180         int tid;
181         int size;
182         int write;
183         int atomic;
184         void *addr;
185         void *trace[REPORT_TRACE_SIZE];
186     } mops[REPORT_ARRAY_SIZE];
187     
188     int loc_count;
189     struct {
190         int idx;
191         const char *type;
192         void *addr;
193         unsigned long start;
194         unsigned long size;
195         int tid;
196         int fd;
197         int suppressable;
198         void *trace[REPORT_TRACE_SIZE];
199     } locs[REPORT_ARRAY_SIZE];
200     
201     int mutex_count;
202     struct {
203         int idx;
204         unsigned long mutex_id;
205         void *addr;
206         int destroyed;
207         void *trace[REPORT_TRACE_SIZE];
208     } mutexes[REPORT_ARRAY_SIZE];
209     
210     int thread_count;
211     struct {
212         int idx;
213         int tid;
214         unsigned long os_id;
215         int running;
216         const char *name;
217         int parent_tid;
218         void *trace[REPORT_TRACE_SIZE];
219     } threads[REPORT_ARRAY_SIZE];
220     
221     int unique_tid_count;
222     struct {
223         int idx;
224         int tid;
225     } unique_tids[REPORT_ARRAY_SIZE];
226 };
227 )";
228
229 const char *
230 thread_sanitizer_retrieve_report_data_command = R"(
231 data t = {0};
232
233 t.report = __tsan_get_current_report();
234 __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);
235
236 if (t.stack_count > REPORT_ARRAY_SIZE) t.stack_count = REPORT_ARRAY_SIZE;
237 for (int i = 0; i < t.stack_count; i++) {
238     t.stacks[i].idx = i;
239     __tsan_get_report_stack(t.report, i, t.stacks[i].trace, REPORT_TRACE_SIZE);
240 }
241
242 if (t.mop_count > REPORT_ARRAY_SIZE) t.mop_count = REPORT_ARRAY_SIZE;
243 for (int i = 0; i < t.mop_count; i++) {
244     t.mops[i].idx = i;
245     __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);
246 }
247
248 if (t.loc_count > REPORT_ARRAY_SIZE) t.loc_count = REPORT_ARRAY_SIZE;
249 for (int i = 0; i < t.loc_count; i++) {
250     t.locs[i].idx = i;
251     __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);
252 }
253
254 if (t.mutex_count > REPORT_ARRAY_SIZE) t.mutex_count = REPORT_ARRAY_SIZE;
255 for (int i = 0; i < t.mutex_count; i++) {
256     t.mutexes[i].idx = i;
257     __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);
258 }
259
260 if (t.thread_count > REPORT_ARRAY_SIZE) t.thread_count = REPORT_ARRAY_SIZE;
261 for (int i = 0; i < t.thread_count; i++) {
262     t.threads[i].idx = i;
263     __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);
264 }
265
266 if (t.unique_tid_count > REPORT_ARRAY_SIZE) t.unique_tid_count = REPORT_ARRAY_SIZE;
267 for (int i = 0; i < t.unique_tid_count; i++) {
268     t.unique_tids[i].idx = i;
269     __tsan_get_report_unique_tid(t.report, i, &t.unique_tids[i].tid);
270 }
271
272 t;
273 )";
274
275 static StructuredData::Array *
276 CreateStackTrace(ValueObjectSP o, std::string trace_item_name = ".trace") {
277     StructuredData::Array *trace = new StructuredData::Array();
278     ValueObjectSP trace_value_object = o->GetValueForExpressionPath(trace_item_name.c_str());
279     for (int j = 0; j < 8; j++) {
280         addr_t trace_addr = trace_value_object->GetChildAtIndex(j, true)->GetValueAsUnsigned(0);
281         if (trace_addr == 0)
282             break;
283         trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(trace_addr)));
284     }
285     return trace;
286 }
287
288 static StructuredData::Array *
289 ConvertToStructuredArray(ValueObjectSP return_value_sp, std::string items_name, std::string count_name, std::function <void(ValueObjectSP o, StructuredData::Dictionary *dict)> const &callback)
290 {
291     StructuredData::Array *array = new StructuredData::Array();
292     unsigned int count = return_value_sp->GetValueForExpressionPath(count_name.c_str())->GetValueAsUnsigned(0);
293     ValueObjectSP objects = return_value_sp->GetValueForExpressionPath(items_name.c_str());
294     for (unsigned int i = 0; i < count; i++) {
295         ValueObjectSP o = objects->GetChildAtIndex(i, true);
296         StructuredData::Dictionary *dict = new StructuredData::Dictionary();
297         
298         callback(o, dict);
299         
300         array->AddItem(StructuredData::ObjectSP(dict));
301     }
302     return array;
303 }
304
305 static std::string
306 RetrieveString(ValueObjectSP return_value_sp, ProcessSP process_sp, std::string expression_path)
307 {
308     addr_t ptr = return_value_sp->GetValueForExpressionPath(expression_path.c_str())->GetValueAsUnsigned(0);
309     std::string str;
310     Error error;
311     process_sp->ReadCStringFromMemory(ptr, str, error);
312     return str;
313 }
314
315 static void
316 GetRenumberedThreadIds(ProcessSP process_sp, ValueObjectSP data, std::map<uint64_t, user_id_t> &thread_id_map)
317 {
318     ConvertToStructuredArray(data, ".threads", ".thread_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
319         uint64_t thread_id = o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0);
320         uint64_t thread_os_id = o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0);
321         user_id_t lldb_user_id = 0;
322         
323         bool can_update = true;
324         ThreadSP lldb_thread = process_sp->GetThreadList().FindThreadByID(thread_os_id, can_update);
325         if (lldb_thread) {
326             lldb_user_id = lldb_thread->GetIndexID();
327         } else {
328             // This isn't a live thread anymore.  Ask process to assign a new Index ID (or return an old one if we've already seen this thread_os_id).
329             // It will also make sure that no new threads are assigned this Index ID.
330             lldb_user_id = process_sp->AssignIndexIDToThread(thread_os_id);
331         }
332         
333         thread_id_map[thread_id] = lldb_user_id;
334     });
335 }
336
337 static user_id_t Renumber(uint64_t id, std::map<uint64_t, user_id_t> &thread_id_map) {
338     if (! thread_id_map.count(id))
339         return 0;
340     
341     return thread_id_map[id];
342 }
343
344 StructuredData::ObjectSP
345 ThreadSanitizerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref)
346 {
347     ProcessSP process_sp = GetProcessSP();
348     if (!process_sp)
349         return StructuredData::ObjectSP();
350     
351     ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
352     StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
353     
354     if (!frame_sp)
355         return StructuredData::ObjectSP();
356     
357     EvaluateExpressionOptions options;
358     options.SetUnwindOnError(true);
359     options.SetTryAllThreads(true);
360     options.SetStopOthers(true);
361     options.SetIgnoreBreakpoints(true);
362     options.SetTimeoutUsec(RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC);
363     options.SetPrefix(thread_sanitizer_retrieve_report_data_prefix);
364     options.SetAutoApplyFixIts(false);
365     options.SetLanguage(eLanguageTypeObjC_plus_plus);
366     
367     ValueObjectSP main_value;
368     ExecutionContext exe_ctx;
369     Error eval_error;
370     frame_sp->CalculateExecutionContext(exe_ctx);
371     ExpressionResults result = UserExpression::Evaluate (exe_ctx,
372                               options,
373                               thread_sanitizer_retrieve_report_data_command,
374                               "",
375                               main_value,
376                               eval_error);
377     if (result != eExpressionCompleted) {
378         process_sp->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: Cannot evaluate ThreadSanitizer expression:\n%s\n", eval_error.AsCString());
379         return StructuredData::ObjectSP();
380     }
381     
382     std::map<uint64_t, user_id_t> thread_id_map;
383     GetRenumberedThreadIds(process_sp, main_value, thread_id_map);
384     
385     StructuredData::Dictionary *dict = new StructuredData::Dictionary();
386     dict->AddStringItem("instrumentation_class", "ThreadSanitizer");
387     dict->AddStringItem("issue_type", RetrieveString(main_value, process_sp, ".description"));
388     dict->AddIntegerItem("report_count", main_value->GetValueForExpressionPath(".report_count")->GetValueAsUnsigned(0));
389     dict->AddItem("sleep_trace", StructuredData::ObjectSP(CreateStackTrace(main_value, ".sleep_trace")));
390     
391     StructuredData::Array *stacks = ConvertToStructuredArray(main_value, ".stacks", ".stack_count", [thread_sp] (ValueObjectSP o, StructuredData::Dictionary *dict) {
392         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
393         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
394         // "stacks" happen on the current thread
395         dict->AddIntegerItem("thread_id", thread_sp->GetIndexID());
396     });
397     dict->AddItem("stacks", StructuredData::ObjectSP(stacks));
398     
399     StructuredData::Array *mops = ConvertToStructuredArray(main_value, ".mops", ".mop_count", [&thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
400         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
401         dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
402         dict->AddIntegerItem("size", o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0));
403         dict->AddBooleanItem("is_write", o->GetValueForExpressionPath(".write")->GetValueAsUnsigned(0));
404         dict->AddBooleanItem("is_atomic", o->GetValueForExpressionPath(".atomic")->GetValueAsUnsigned(0));
405         dict->AddIntegerItem("address", o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0));
406         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
407     });
408     dict->AddItem("mops", StructuredData::ObjectSP(mops));
409     
410     StructuredData::Array *locs = ConvertToStructuredArray(main_value, ".locs", ".loc_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
411         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
412         dict->AddStringItem("type", RetrieveString(o, process_sp, ".type"));
413         dict->AddIntegerItem("address", o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0));
414         dict->AddIntegerItem("start", o->GetValueForExpressionPath(".start")->GetValueAsUnsigned(0));
415         dict->AddIntegerItem("size", o->GetValueForExpressionPath(".size")->GetValueAsUnsigned(0));
416         dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
417         dict->AddIntegerItem("file_descriptor", o->GetValueForExpressionPath(".fd")->GetValueAsUnsigned(0));
418         dict->AddIntegerItem("suppressable", o->GetValueForExpressionPath(".suppressable")->GetValueAsUnsigned(0));
419         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
420     });
421     dict->AddItem("locs", StructuredData::ObjectSP(locs));
422     
423     StructuredData::Array *mutexes = ConvertToStructuredArray(main_value, ".mutexes", ".mutex_count", [] (ValueObjectSP o, StructuredData::Dictionary *dict) {
424         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
425         dict->AddIntegerItem("mutex_id", o->GetValueForExpressionPath(".mutex_id")->GetValueAsUnsigned(0));
426         dict->AddIntegerItem("address", o->GetValueForExpressionPath(".addr")->GetValueAsUnsigned(0));
427         dict->AddIntegerItem("destroyed", o->GetValueForExpressionPath(".destroyed")->GetValueAsUnsigned(0));
428         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
429     });
430     dict->AddItem("mutexes", StructuredData::ObjectSP(mutexes));
431     
432     StructuredData::Array *threads = ConvertToStructuredArray(main_value, ".threads", ".thread_count", [process_sp, &thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
433         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
434         dict->AddIntegerItem("thread_id", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
435         dict->AddIntegerItem("thread_os_id", o->GetValueForExpressionPath(".os_id")->GetValueAsUnsigned(0));
436         dict->AddIntegerItem("running", o->GetValueForExpressionPath(".running")->GetValueAsUnsigned(0));
437         dict->AddStringItem("name", RetrieveString(o, process_sp, ".name"));
438         dict->AddIntegerItem("parent_thread_id", Renumber(o->GetValueForExpressionPath(".parent_tid")->GetValueAsUnsigned(0), thread_id_map));
439         dict->AddItem("trace", StructuredData::ObjectSP(CreateStackTrace(o)));
440     });
441     dict->AddItem("threads", StructuredData::ObjectSP(threads));
442     
443     StructuredData::Array *unique_tids = ConvertToStructuredArray(main_value, ".unique_tids", ".unique_tid_count", [&thread_id_map] (ValueObjectSP o, StructuredData::Dictionary *dict) {
444         dict->AddIntegerItem("index", o->GetValueForExpressionPath(".idx")->GetValueAsUnsigned(0));
445         dict->AddIntegerItem("tid", Renumber(o->GetValueForExpressionPath(".tid")->GetValueAsUnsigned(0), thread_id_map));
446     });
447     dict->AddItem("unique_tids", StructuredData::ObjectSP(unique_tids));
448     
449     return StructuredData::ObjectSP(dict);
450 }
451
452 std::string
453 ThreadSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report)
454 {
455     std::string description = report->GetAsDictionary()->GetValueForKey("issue_type")->GetAsString()->GetValue();
456     
457     if (description == "data-race") {
458         return "Data race";
459     } else if (description == "data-race-vptr") {
460         return "Data race on C++ virtual pointer";
461     } else if (description == "heap-use-after-free") {
462         return "Use of deallocated memory";
463     } else if (description == "heap-use-after-free-vptr") {
464         return "Use of deallocated C++ virtual pointer";
465     } else if (description == "thread-leak") {
466         return "Thread leak";
467     } else if (description == "locked-mutex-destroy") {
468         return "Destruction of a locked mutex";
469     } else if (description == "mutex-double-lock") {
470         return "Double lock of a mutex";
471     } else if (description == "mutex-invalid-access") {
472         return "Use of an uninitialized or destroyed mutex";
473     } else if (description == "mutex-bad-unlock") {
474         return "Unlock of an unlocked mutex (or by a wrong thread)";
475     } else if (description == "mutex-bad-read-lock") {
476         return "Read lock of a write locked mutex";
477     } else if (description == "mutex-bad-read-unlock") {
478         return "Read unlock of a write locked mutex";
479     } else if (description == "signal-unsafe-call") {
480         return "Signal-unsafe call inside a signal handler";
481     } else if (description == "errno-in-signal-handler") {
482         return "Overwrite of errno in a signal handler";
483     } else if (description == "lock-order-inversion") {
484         return "Lock order inversion (potential deadlock)";
485     }
486     
487     // for unknown report codes just show the code
488     return description;
489 }
490
491 static std::string
492 Sprintf(const char *format, ...)
493 {
494     StreamString s;
495     va_list args;
496     va_start (args, format);
497     s.PrintfVarArg(format, args);
498     va_end (args);
499     return s.GetString();
500 }
501
502 static std::string
503 GetSymbolNameFromAddress(ProcessSP process_sp, addr_t addr)
504 {
505     lldb_private::Address so_addr;
506     if (! process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
507         return "";
508     
509     lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol();
510     if (! symbol)
511         return "";
512     
513     std::string sym_name = symbol->GetName().GetCString();
514     return sym_name;
515 }
516
517 static void
518 GetSymbolDeclarationFromAddress(ProcessSP process_sp, addr_t addr, Declaration &decl)
519 {
520     lldb_private::Address so_addr;
521     if (! process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
522         return;
523     
524     lldb_private::Symbol *symbol = so_addr.CalculateSymbolContextSymbol();
525     if (! symbol)
526         return;
527     
528     ConstString sym_name = symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled);
529     
530     ModuleSP module = symbol->CalculateSymbolContextModule();
531     if (! module)
532         return;
533     
534     VariableList var_list;
535     module->FindGlobalVariables(sym_name, nullptr, true, 1U, var_list);
536     if (var_list.GetSize() < 1)
537         return;
538     
539     VariableSP var = var_list.GetVariableAtIndex(0);
540     decl = var->GetDeclaration();
541 }
542
543 addr_t
544 ThreadSanitizerRuntime::GetFirstNonInternalFramePc(StructuredData::ObjectSP trace)
545 {
546     ProcessSP process_sp = GetProcessSP();
547     ModuleSP runtime_module_sp = GetRuntimeModuleSP();
548     
549     addr_t result = 0;
550     trace->GetAsArray()->ForEach([process_sp, runtime_module_sp, &result] (StructuredData::Object *o) -> bool {
551         addr_t addr = o->GetIntegerValue();
552         lldb_private::Address so_addr;
553         if (! process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
554             return true;
555         
556         if (so_addr.GetModule() == runtime_module_sp)
557             return true;
558         
559         result = addr;
560         return false;
561     });
562     
563     return result;
564 }
565
566 std::string
567 ThreadSanitizerRuntime::GenerateSummary(StructuredData::ObjectSP report)
568 {
569     ProcessSP process_sp = GetProcessSP();
570     
571     std::string summary = report->GetAsDictionary()->GetValueForKey("description")->GetAsString()->GetValue();
572     addr_t pc = 0;
573     if (report->GetAsDictionary()->GetValueForKey("mops")->GetAsArray()->GetSize() > 0)
574         pc = GetFirstNonInternalFramePc(report->GetAsDictionary()->GetValueForKey("mops")->GetAsArray()->GetItemAtIndex(0)->GetAsDictionary()->GetValueForKey("trace"));
575
576     if (report->GetAsDictionary()->GetValueForKey("stacks")->GetAsArray()->GetSize() > 0)
577         pc = GetFirstNonInternalFramePc(report->GetAsDictionary()->GetValueForKey("stacks")->GetAsArray()->GetItemAtIndex(0)->GetAsDictionary()->GetValueForKey("trace"));
578
579     if (pc != 0) {
580         summary = summary + " in " + GetSymbolNameFromAddress(process_sp, pc);
581     }
582     
583     if (report->GetAsDictionary()->GetValueForKey("locs")->GetAsArray()->GetSize() > 0) {
584         StructuredData::ObjectSP loc = report->GetAsDictionary()->GetValueForKey("locs")->GetAsArray()->GetItemAtIndex(0);
585         addr_t addr = loc->GetAsDictionary()->GetValueForKey("address")->GetAsInteger()->GetValue();
586         if (addr == 0)
587             addr = loc->GetAsDictionary()->GetValueForKey("start")->GetAsInteger()->GetValue();
588         
589         if (addr != 0) {
590             std::string global_name = GetSymbolNameFromAddress(process_sp, addr);
591             if (!global_name.empty()) {
592                 summary = summary + " at " + global_name;
593             } else {
594                 summary = summary + " at " + Sprintf("0x%llx", addr);
595             }
596         } else {
597             int fd = loc->GetAsDictionary()->GetValueForKey("file_descriptor")->GetAsInteger()->GetValue();
598             if (fd != 0) {
599                 summary = summary + " on file descriptor " + Sprintf("%d", fd);
600             }
601         }
602     }
603     
604     return summary;
605 }
606
607 addr_t
608 ThreadSanitizerRuntime::GetMainRacyAddress(StructuredData::ObjectSP report)
609 {
610     addr_t result = (addr_t)-1;
611     
612     report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach([&result] (StructuredData::Object *o) -> bool {
613         addr_t addr = o->GetObjectForDotSeparatedPath("address")->GetIntegerValue();
614         if (addr < result) result = addr;
615         return true;
616     });
617
618     return (result == (addr_t)-1) ? 0 : result;
619 }
620
621 std::string
622 ThreadSanitizerRuntime::GetLocationDescription(StructuredData::ObjectSP report, addr_t &global_addr, std::string &global_name, std::string &filename, uint32_t &line)
623 {
624     std::string result = "";
625     
626     ProcessSP process_sp = GetProcessSP();
627     
628     if (report->GetAsDictionary()->GetValueForKey("locs")->GetAsArray()->GetSize() > 0) {
629         StructuredData::ObjectSP loc = report->GetAsDictionary()->GetValueForKey("locs")->GetAsArray()->GetItemAtIndex(0);
630         std::string type = loc->GetAsDictionary()->GetValueForKey("type")->GetStringValue();
631         if (type == "global") {
632             global_addr = loc->GetAsDictionary()->GetValueForKey("address")->GetAsInteger()->GetValue();
633             global_name = GetSymbolNameFromAddress(process_sp, global_addr);
634             if (!global_name.empty()) {
635                 result = Sprintf("'%s' is a global variable (0x%llx)", global_name.c_str(), global_addr);
636             } else {
637                 result = Sprintf("0x%llx is a global variable", global_addr);
638             }
639             
640             Declaration decl;
641             GetSymbolDeclarationFromAddress(process_sp, global_addr, decl);
642             if (decl.GetFile()) {
643                 filename = decl.GetFile().GetPath();
644                 line = decl.GetLine();
645             }
646         } else if (type == "heap") {
647             addr_t addr = loc->GetAsDictionary()->GetValueForKey("start")->GetAsInteger()->GetValue();
648             long size = loc->GetAsDictionary()->GetValueForKey("size")->GetAsInteger()->GetValue();
649             result = Sprintf("Location is a %ld-byte heap object at 0x%llx", size, addr);
650         } else if (type == "stack") {
651             int tid = loc->GetAsDictionary()->GetValueForKey("thread_id")->GetAsInteger()->GetValue();
652             result = Sprintf("Location is stack of thread %d", tid);
653         } else if (type == "tls") {
654             int tid = loc->GetAsDictionary()->GetValueForKey("thread_id")->GetAsInteger()->GetValue();
655             result = Sprintf("Location is TLS of thread %d", tid);
656         } else if (type == "fd") {
657             int fd = loc->GetAsDictionary()->GetValueForKey("file_descriptor")->GetAsInteger()->GetValue();
658             result = Sprintf("Location is file descriptor %d", fd);
659         }
660     }
661     
662     return result;
663 }
664
665 bool
666 ThreadSanitizerRuntime::NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id)
667 {
668     assert (baton && "null baton");
669     if (!baton)
670         return false;
671     
672     ThreadSanitizerRuntime *const instance = static_cast<ThreadSanitizerRuntime*>(baton);
673     
674     StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref);
675     std::string stop_reason_description;
676     if (report) {
677         std::string issue_description = instance->FormatDescription(report);
678         report->GetAsDictionary()->AddStringItem("description", issue_description);
679         stop_reason_description = issue_description + " detected";
680         report->GetAsDictionary()->AddStringItem("stop_description", stop_reason_description);
681         std::string summary = instance->GenerateSummary(report);
682         report->GetAsDictionary()->AddStringItem("summary", summary);
683         addr_t main_address = instance->GetMainRacyAddress(report);
684         report->GetAsDictionary()->AddIntegerItem("memory_address", main_address);
685         
686         addr_t global_addr = 0;
687         std::string global_name = "";
688         std::string location_filename = "";
689         uint32_t location_line = 0;
690         std::string location_description = instance->GetLocationDescription(report, global_addr, global_name, location_filename, location_line);
691         report->GetAsDictionary()->AddStringItem("location_description", location_description);
692         if (global_addr != 0) {
693             report->GetAsDictionary()->AddIntegerItem("global_address", global_addr);
694         }
695         if (!global_name.empty()) {
696             report->GetAsDictionary()->AddStringItem("global_name", global_name);
697         }
698         if (location_filename != "") {
699             report->GetAsDictionary()->AddStringItem("location_filename", location_filename);
700             report->GetAsDictionary()->AddIntegerItem("location_line", location_line);
701         }
702         
703         bool all_addresses_are_same = true;
704         report->GetObjectForDotSeparatedPath("mops")->GetAsArray()->ForEach([&all_addresses_are_same, main_address] (StructuredData::Object *o) -> bool {
705             addr_t addr = o->GetObjectForDotSeparatedPath("address")->GetIntegerValue();
706             if (main_address != addr) all_addresses_are_same = false;
707             return true;
708         });
709         report->GetAsDictionary()->AddBooleanItem("all_addresses_are_same", all_addresses_are_same);
710     }
711     
712     ProcessSP process_sp = instance->GetProcessSP();
713     // Make sure this is the right process
714     if (process_sp && process_sp == context->exe_ctx_ref.GetProcessSP())
715     {
716         ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
717         if (thread_sp)
718             thread_sp->SetStopInfo(InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(*thread_sp, stop_reason_description.c_str(), report));
719         
720         StreamFileSP stream_sp (process_sp->GetTarget().GetDebugger().GetOutputFile());
721         if (stream_sp)
722         {
723             stream_sp->Printf ("ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.\n");
724         }
725         return true;    // Return true to stop the target
726     }
727     else
728         return false;   // Let target run
729 }
730
731 void
732 ThreadSanitizerRuntime::Activate()
733 {
734     if (m_is_active)
735         return;
736     
737     ProcessSP process_sp = GetProcessSP();
738     if (!process_sp)
739         return;
740     
741     ConstString symbol_name ("__tsan_on_report");
742     const Symbol *symbol = GetRuntimeModuleSP()->FindFirstSymbolWithNameAndType (symbol_name, eSymbolTypeCode);
743     
744     if (symbol == NULL)
745         return;
746     
747     if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
748         return;
749     
750     Target &target = process_sp->GetTarget();
751     addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
752     
753     if (symbol_address == LLDB_INVALID_ADDRESS)
754         return;
755     
756     bool internal = true;
757     bool hardware = false;
758     Breakpoint *breakpoint = process_sp->GetTarget().CreateBreakpoint(symbol_address, internal, hardware).get();
759     breakpoint->SetCallback (ThreadSanitizerRuntime::NotifyBreakpointHit, this, true);
760     breakpoint->SetBreakpointKind ("thread-sanitizer-report");
761     m_breakpoint_id = breakpoint->GetID();
762     
763     StreamFileSP stream_sp (process_sp->GetTarget().GetDebugger().GetOutputFile());
764     if (stream_sp)
765     {
766         stream_sp->Printf ("ThreadSanitizer debugger support is active.\n");
767     }
768     
769     m_is_active = true;
770 }
771
772 void
773 ThreadSanitizerRuntime::Deactivate()
774 {
775     if (m_breakpoint_id != LLDB_INVALID_BREAK_ID)
776     {
777         ProcessSP process_sp = GetProcessSP();
778         if (process_sp)
779         {
780             process_sp->GetTarget().RemoveBreakpointByID(m_breakpoint_id);
781             m_breakpoint_id = LLDB_INVALID_BREAK_ID;
782         }
783     }
784     m_is_active = false;
785 }
786
787 static std::string
788 GenerateThreadName(std::string path, StructuredData::Object *o, StructuredData::ObjectSP main_info) {
789     std::string result = "additional information";
790     
791     if (path == "mops") {
792         int size = o->GetObjectForDotSeparatedPath("size")->GetIntegerValue();
793         int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue();
794         bool is_write = o->GetObjectForDotSeparatedPath("is_write")->GetBooleanValue();
795         bool is_atomic = o->GetObjectForDotSeparatedPath("is_atomic")->GetBooleanValue();
796         addr_t addr = o->GetObjectForDotSeparatedPath("address")->GetIntegerValue();
797         
798         std::string addr_string = Sprintf(" at 0x%llx", addr);
799         
800         if (main_info->GetObjectForDotSeparatedPath("all_addresses_are_same")->GetBooleanValue()){
801             addr_string = "";
802         }
803         
804         result = Sprintf("%s%s of size %d%s by thread %d", is_atomic ? "atomic " : "", is_write ? "write" : "read", size, addr_string.c_str(), thread_id);
805     }
806     
807     if (path == "threads") {
808         int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue();
809         result = Sprintf("Thread %d created", thread_id);
810     }
811     
812     if (path == "locs") {
813         std::string type = o->GetAsDictionary()->GetValueForKey("type")->GetStringValue();
814         int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue();
815         int fd = o->GetObjectForDotSeparatedPath("file_descriptor")->GetIntegerValue();
816         if (type == "heap") {
817             result = Sprintf("Heap block allocated by thread %d", thread_id);
818         } else if (type == "fd") {
819             result = Sprintf("File descriptor %d created by thread %t", fd, thread_id);
820         }
821     }
822     
823     if (path == "mutexes") {
824         int mutex_id = o->GetObjectForDotSeparatedPath("mutex_id")->GetIntegerValue();
825         
826         result = Sprintf("Mutex M%d created", mutex_id);
827     }
828     
829     if (path == "stacks") {
830         int thread_id = o->GetObjectForDotSeparatedPath("thread_id")->GetIntegerValue();
831         result = Sprintf("Thread %d", thread_id);
832     }
833     
834     result[0] = toupper(result[0]);
835     
836     return result;
837 }
838
839 static void
840 AddThreadsForPath(std::string path, ThreadCollectionSP threads, ProcessSP process_sp, StructuredData::ObjectSP info)
841 {
842     info->GetObjectForDotSeparatedPath(path)->GetAsArray()->ForEach([process_sp, threads, path, info] (StructuredData::Object *o) -> bool {
843         std::vector<lldb::addr_t> pcs;
844         o->GetObjectForDotSeparatedPath("trace")->GetAsArray()->ForEach([&pcs] (StructuredData::Object *pc) -> bool {
845             pcs.push_back(pc->GetAsInteger()->GetValue());
846             return true;
847         });
848         
849         if (pcs.size() == 0)
850             return true;
851         
852         StructuredData::ObjectSP thread_id_obj = o->GetObjectForDotSeparatedPath("thread_os_id");
853         tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
854         
855         uint32_t stop_id = 0;
856         bool stop_id_is_valid = false;
857         HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs, stop_id, stop_id_is_valid);
858         ThreadSP new_thread_sp(history_thread);
859         new_thread_sp->SetName(GenerateThreadName(path, o, info).c_str());
860         
861         // Save this in the Process' ExtendedThreadList so a strong pointer retains the object
862         process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
863         threads->AddThread(new_thread_sp);
864         
865         return true;
866     });
867 }
868
869 lldb::ThreadCollectionSP
870 ThreadSanitizerRuntime::GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info)
871 {
872     ThreadCollectionSP threads;
873     threads.reset(new ThreadCollection());
874
875     if (info->GetObjectForDotSeparatedPath("instrumentation_class")->GetStringValue() != "ThreadSanitizer")
876         return threads;
877     
878     ProcessSP process_sp = GetProcessSP();
879     
880     AddThreadsForPath("stacks", threads, process_sp, info);
881     AddThreadsForPath("mops", threads, process_sp, info);
882     AddThreadsForPath("locs", threads, process_sp, info);
883     AddThreadsForPath("mutexes", threads, process_sp, info);
884     AddThreadsForPath("threads", threads, process_sp, info);
885     
886     return threads;
887 }