]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / OperatingSystem / Go / OperatingSystemGo.cpp
1 //===-- OperatingSystemGo.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 // C Includes
11 // C++ Includes
12 #include <unordered_map>
13
14 // Other libraries and framework includes
15 // Project includes
16 #include "OperatingSystemGo.h"
17
18 #include "Plugins/Process/Utility/DynamicRegisterInfo.h"
19 #include "Plugins/Process/Utility/RegisterContextMemory.h"
20 #include "Plugins/Process/Utility/ThreadMemory.h"
21 #include "lldb/Core/Debugger.h"
22 #include "lldb/Core/Module.h"
23 #include "lldb/Core/PluginManager.h"
24 #include "lldb/Core/RegisterValue.h"
25 #include "lldb/Core/Section.h"
26 #include "lldb/Core/ValueObjectVariable.h"
27 #include "lldb/Interpreter/CommandInterpreter.h"
28 #include "lldb/Interpreter/OptionGroupBoolean.h"
29 #include "lldb/Interpreter/OptionGroupUInt64.h"
30 #include "lldb/Interpreter/OptionValueProperties.h"
31 #include "lldb/Interpreter/Options.h"
32 #include "lldb/Interpreter/Property.h"
33 #include "lldb/Symbol/ObjectFile.h"
34 #include "lldb/Symbol/Type.h"
35 #include "lldb/Symbol/VariableList.h"
36 #include "lldb/Target/Process.h"
37 #include "lldb/Target/StopInfo.h"
38 #include "lldb/Target/Target.h"
39 #include "lldb/Target/Thread.h"
40 #include "lldb/Target/ThreadList.h"
41 #include "lldb/Utility/DataBufferHeap.h"
42 #include "lldb/Utility/StreamString.h"
43
44 using namespace lldb;
45 using namespace lldb_private;
46
47 namespace {
48
49 static PropertyDefinition g_properties[] = {
50     {"enable", OptionValue::eTypeBoolean, true, true, nullptr, nullptr,
51      "Specify whether goroutines should be treated as threads."},
52     {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}};
53
54 enum {
55   ePropertyEnableGoroutines,
56 };
57
58 class PluginProperties : public Properties {
59 public:
60   PluginProperties() : Properties() {
61     m_collection_sp.reset(new OptionValueProperties(GetSettingName()));
62     m_collection_sp->Initialize(g_properties);
63   }
64
65   ~PluginProperties() override = default;
66
67   static ConstString GetSettingName() {
68     return OperatingSystemGo::GetPluginNameStatic();
69   }
70
71   bool GetEnableGoroutines() {
72     const uint32_t idx = ePropertyEnableGoroutines;
73     return m_collection_sp->GetPropertyAtIndexAsBoolean(
74         NULL, idx, g_properties[idx].default_uint_value);
75   }
76
77   bool SetEnableGoroutines(bool enable) {
78     const uint32_t idx = ePropertyEnableGoroutines;
79     return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, enable);
80   }
81 };
82
83 typedef std::shared_ptr<PluginProperties> OperatingSystemGoPropertiesSP;
84
85 static const OperatingSystemGoPropertiesSP &GetGlobalPluginProperties() {
86   static OperatingSystemGoPropertiesSP g_settings_sp;
87   if (!g_settings_sp)
88     g_settings_sp.reset(new PluginProperties());
89   return g_settings_sp;
90 }
91
92 class RegisterContextGo : public RegisterContextMemory {
93 public:
94   RegisterContextGo(lldb_private::Thread &thread, uint32_t concrete_frame_idx,
95                     DynamicRegisterInfo &reg_info, lldb::addr_t reg_data_addr)
96       : RegisterContextMemory(thread, concrete_frame_idx, reg_info,
97                               reg_data_addr) {
98     const RegisterInfo *sp = reg_info.GetRegisterInfoAtIndex(
99         reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
100                                                      LLDB_REGNUM_GENERIC_SP));
101     const RegisterInfo *pc = reg_info.GetRegisterInfoAtIndex(
102         reg_info.ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
103                                                      LLDB_REGNUM_GENERIC_PC));
104     size_t byte_size = std::max(sp->byte_offset + sp->byte_size,
105                                 pc->byte_offset + pc->byte_size);
106
107     DataBufferSP reg_data_sp(new DataBufferHeap(byte_size, 0));
108     m_reg_data.SetData(reg_data_sp);
109   }
110
111   ~RegisterContextGo() override = default;
112
113   bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
114                     lldb_private::RegisterValue &reg_value) override {
115     switch (reg_info->kinds[eRegisterKindGeneric]) {
116     case LLDB_REGNUM_GENERIC_SP:
117     case LLDB_REGNUM_GENERIC_PC:
118       return RegisterContextMemory::ReadRegister(reg_info, reg_value);
119     default:
120       reg_value.SetValueToInvalid();
121       return true;
122     }
123   }
124
125   bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
126                      const lldb_private::RegisterValue &reg_value) override {
127     switch (reg_info->kinds[eRegisterKindGeneric]) {
128     case LLDB_REGNUM_GENERIC_SP:
129     case LLDB_REGNUM_GENERIC_PC:
130       return RegisterContextMemory::WriteRegister(reg_info, reg_value);
131     default:
132       return false;
133     }
134   }
135
136 private:
137   DISALLOW_COPY_AND_ASSIGN(RegisterContextGo);
138 };
139
140 } // anonymous namespace
141
142 struct OperatingSystemGo::Goroutine {
143   uint64_t m_lostack;
144   uint64_t m_histack;
145   uint64_t m_goid;
146   addr_t m_gobuf;
147   uint32_t m_status;
148 };
149
150 void OperatingSystemGo::Initialize() {
151   PluginManager::RegisterPlugin(GetPluginNameStatic(),
152                                 GetPluginDescriptionStatic(), CreateInstance,
153                                 DebuggerInitialize);
154 }
155
156 void OperatingSystemGo::DebuggerInitialize(Debugger &debugger) {
157   if (!PluginManager::GetSettingForOperatingSystemPlugin(
158           debugger, PluginProperties::GetSettingName())) {
159     const bool is_global_setting = true;
160     PluginManager::CreateSettingForOperatingSystemPlugin(
161         debugger, GetGlobalPluginProperties()->GetValueProperties(),
162         ConstString("Properties for the goroutine thread plug-in."),
163         is_global_setting);
164   }
165 }
166
167 void OperatingSystemGo::Terminate() {
168   PluginManager::UnregisterPlugin(CreateInstance);
169 }
170
171 OperatingSystem *OperatingSystemGo::CreateInstance(Process *process,
172                                                    bool force) {
173   if (!force) {
174     TargetSP target_sp = process->CalculateTarget();
175     if (!target_sp)
176       return nullptr;
177     ModuleList &module_list = target_sp->GetImages();
178     std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
179     const size_t num_modules = module_list.GetSize();
180     bool found_go_runtime = false;
181     for (size_t i = 0; i < num_modules; ++i) {
182       Module *module = module_list.GetModulePointerAtIndexUnlocked(i);
183       const SectionList *section_list = module->GetSectionList();
184       if (section_list) {
185         SectionSP section_sp(
186             section_list->FindSectionByType(eSectionTypeGoSymtab, true));
187         if (section_sp) {
188           found_go_runtime = true;
189           break;
190         }
191       }
192     }
193     if (!found_go_runtime)
194       return nullptr;
195   }
196   return new OperatingSystemGo(process);
197 }
198
199 OperatingSystemGo::OperatingSystemGo(lldb_private::Process *process)
200     : OperatingSystem(process), m_reginfo(new DynamicRegisterInfo) {}
201
202 OperatingSystemGo::~OperatingSystemGo() = default;
203
204 ConstString OperatingSystemGo::GetPluginNameStatic() {
205   static ConstString g_name("goroutines");
206   return g_name;
207 }
208
209 const char *OperatingSystemGo::GetPluginDescriptionStatic() {
210   return "Operating system plug-in that reads runtime data-structures for "
211          "goroutines.";
212 }
213
214 bool OperatingSystemGo::Init(ThreadList &threads) {
215   if (threads.GetSize(false) < 1)
216     return false;
217   TargetSP target_sp = m_process->CalculateTarget();
218   if (!target_sp)
219     return false;
220   // Go 1.6 stores goroutines in a slice called runtime.allgs
221   ValueObjectSP allgs_sp = FindGlobal(target_sp, "runtime.allgs");
222   if (allgs_sp) {
223     m_allg_sp = allgs_sp->GetChildMemberWithName(ConstString("array"), true);
224     m_allglen_sp = allgs_sp->GetChildMemberWithName(ConstString("len"), true);
225   } else {
226     // Go 1.4 stores goroutines in the variable runtime.allg.
227     m_allg_sp = FindGlobal(target_sp, "runtime.allg");
228     m_allglen_sp = FindGlobal(target_sp, "runtime.allglen");
229   }
230
231   if (m_allg_sp && !m_allglen_sp) {
232     StreamSP error_sp = target_sp->GetDebugger().GetAsyncErrorStream();
233     error_sp->Printf("Unsupported Go runtime version detected.");
234     return false;
235   }
236
237   if (!m_allg_sp)
238     return false;
239
240   RegisterContextSP real_registers_sp =
241       threads.GetThreadAtIndex(0, false)->GetRegisterContext();
242
243   std::unordered_map<size_t, ConstString> register_sets;
244   for (size_t set_idx = 0; set_idx < real_registers_sp->GetRegisterSetCount();
245        ++set_idx) {
246     const RegisterSet *set = real_registers_sp->GetRegisterSet(set_idx);
247     ConstString name(set->name);
248     for (size_t reg_idx = 0; reg_idx < set->num_registers; ++reg_idx) {
249       register_sets[reg_idx] = name;
250     }
251   }
252   TypeSP gobuf_sp = FindType(target_sp, "runtime.gobuf");
253   if (!gobuf_sp) {
254     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
255
256     if (log)
257       log->Printf("OperatingSystemGo unable to find struct Gobuf");
258     return false;
259   }
260   CompilerType gobuf_type(gobuf_sp->GetLayoutCompilerType());
261   for (size_t idx = 0; idx < real_registers_sp->GetRegisterCount(); ++idx) {
262     RegisterInfo reg = *real_registers_sp->GetRegisterInfoAtIndex(idx);
263     int field_index = -1;
264     if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) {
265       field_index = 0;
266     } else if (reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) {
267       field_index = 1;
268     }
269     if (field_index == -1) {
270       reg.byte_offset = ~0;
271     } else {
272       std::string field_name;
273       uint64_t bit_offset = 0;
274       CompilerType field_type = gobuf_type.GetFieldAtIndex(
275           field_index, field_name, &bit_offset, nullptr, nullptr);
276       reg.byte_size = field_type.GetByteSize(nullptr);
277       reg.byte_offset = bit_offset / 8;
278     }
279     ConstString name(reg.name);
280     ConstString alt_name(reg.alt_name);
281     m_reginfo->AddRegister(reg, name, alt_name, register_sets[idx]);
282   }
283   return true;
284 }
285
286 //------------------------------------------------------------------
287 // PluginInterface protocol
288 //------------------------------------------------------------------
289 ConstString OperatingSystemGo::GetPluginName() { return GetPluginNameStatic(); }
290
291 uint32_t OperatingSystemGo::GetPluginVersion() { return 1; }
292
293 bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list,
294                                          ThreadList &real_thread_list,
295                                          ThreadList &new_thread_list) {
296   new_thread_list = real_thread_list;
297   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
298
299   if (!(m_allg_sp || Init(real_thread_list)) || (m_allg_sp && !m_allglen_sp) ||
300       !GetGlobalPluginProperties()->GetEnableGoroutines()) {
301     return new_thread_list.GetSize(false) > 0;
302   }
303
304   if (log)
305     log->Printf("OperatingSystemGo::UpdateThreadList(%d, %d, %d) fetching "
306                 "thread data from Go for pid %" PRIu64,
307                 old_thread_list.GetSize(false), real_thread_list.GetSize(false),
308                 new_thread_list.GetSize(0), m_process->GetID());
309   uint64_t allglen = m_allglen_sp->GetValueAsUnsigned(0);
310   if (allglen == 0) {
311     return new_thread_list.GetSize(false) > 0;
312   }
313   std::vector<Goroutine> goroutines;
314   // The threads that are in "new_thread_list" upon entry are the threads from
315   // the lldb_private::Process subclass, no memory threads will be in this
316   // list.
317
318   Status err;
319   for (uint64_t i = 0; i < allglen; ++i) {
320     goroutines.push_back(CreateGoroutineAtIndex(i, err));
321     if (err.Fail()) {
322       LLDB_LOG(log, "error: {0}", err);
323       return new_thread_list.GetSize(false) > 0;
324     }
325   }
326   // Make a map so we can match goroutines with backing threads.
327   std::map<uint64_t, ThreadSP> stack_map;
328   for (uint32_t i = 0; i < real_thread_list.GetSize(false); ++i) {
329     ThreadSP thread = real_thread_list.GetThreadAtIndex(i, false);
330     stack_map[thread->GetRegisterContext()->GetSP()] = thread;
331   }
332   for (const Goroutine &goroutine : goroutines) {
333     if (0 /* Gidle */ == goroutine.m_status ||
334         6 /* Gdead */ == goroutine.m_status) {
335       continue;
336     }
337     ThreadSP memory_thread =
338         old_thread_list.FindThreadByID(goroutine.m_goid, false);
339     if (memory_thread && IsOperatingSystemPluginThread(memory_thread) &&
340         memory_thread->IsValid()) {
341       memory_thread->ClearBackingThread();
342     } else {
343       memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, "", "",
344                                            goroutine.m_gobuf));
345     }
346     // Search for the backing thread if the goroutine is running.
347     if (2 == (goroutine.m_status & 0xfff)) {
348       auto backing_it = stack_map.lower_bound(goroutine.m_lostack);
349       if (backing_it != stack_map.end()) {
350         if (goroutine.m_histack >= backing_it->first) {
351           if (log)
352             log->Printf(
353                 "OperatingSystemGo::UpdateThreadList found backing thread "
354                 "%" PRIx64 " (%" PRIx64 ") for thread %" PRIx64 "",
355                 backing_it->second->GetID(),
356                 backing_it->second->GetProtocolID(), memory_thread->GetID());
357           memory_thread->SetBackingThread(backing_it->second);
358           new_thread_list.RemoveThreadByID(backing_it->second->GetID(), false);
359         }
360       }
361     }
362     new_thread_list.AddThread(memory_thread);
363   }
364
365   return new_thread_list.GetSize(false) > 0;
366 }
367
368 void OperatingSystemGo::ThreadWasSelected(Thread *thread) {}
369
370 RegisterContextSP
371 OperatingSystemGo::CreateRegisterContextForThread(Thread *thread,
372                                                   addr_t reg_data_addr) {
373   RegisterContextSP reg_ctx_sp;
374   if (!thread)
375     return reg_ctx_sp;
376
377   if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
378     return reg_ctx_sp;
379
380   reg_ctx_sp.reset(
381       new RegisterContextGo(*thread, 0, *m_reginfo, reg_data_addr));
382   return reg_ctx_sp;
383 }
384
385 StopInfoSP
386 OperatingSystemGo::CreateThreadStopReason(lldb_private::Thread *thread) {
387   StopInfoSP stop_info_sp;
388   return stop_info_sp;
389 }
390
391 lldb::ThreadSP OperatingSystemGo::CreateThread(lldb::tid_t tid,
392                                                addr_t context) {
393   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
394
395   if (log)
396     log->Printf("OperatingSystemGo::CreateThread (tid = 0x%" PRIx64
397                 ", context = 0x%" PRIx64 ") not implemented",
398                 tid, context);
399
400   return ThreadSP();
401 }
402
403 ValueObjectSP OperatingSystemGo::FindGlobal(TargetSP target, const char *name) {
404   VariableList variable_list;
405
406   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
407
408   if (log) {
409     log->Printf(
410         "exe: %s",
411         target->GetExecutableModule()->GetSpecificationDescription().c_str());
412     log->Printf("modules: %zu", target->GetImages().GetSize());
413   }
414
415   uint32_t match_count = target->GetImages().FindGlobalVariables(
416       ConstString(name), 1, variable_list);
417   if (match_count > 0) {
418     ExecutionContextScope *exe_scope = target->GetProcessSP().get();
419     if (exe_scope == NULL)
420       exe_scope = target.get();
421     return ValueObjectVariable::Create(exe_scope,
422                                        variable_list.GetVariableAtIndex(0));
423   }
424   return ValueObjectSP();
425 }
426
427 TypeSP OperatingSystemGo::FindType(TargetSP target_sp, const char *name) {
428   ConstString const_typename(name);
429   SymbolContext sc;
430   const bool exact_match = false;
431
432   const ModuleList &module_list = target_sp->GetImages();
433   size_t count = module_list.GetSize();
434   for (size_t idx = 0; idx < count; idx++) {
435     ModuleSP module_sp(module_list.GetModuleAtIndex(idx));
436     if (module_sp) {
437       TypeSP type_sp(module_sp->FindFirstType(sc, const_typename, exact_match));
438       if (type_sp)
439         return type_sp;
440     }
441   }
442   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));
443
444   if (log)
445     log->Printf("OperatingSystemGo::FindType(%s): not found", name);
446   return TypeSP();
447 }
448
449 OperatingSystemGo::Goroutine
450 OperatingSystemGo::CreateGoroutineAtIndex(uint64_t idx, Status &err) {
451   err.Clear();
452   Goroutine result = {};
453   ValueObjectSP g =
454       m_allg_sp->GetSyntheticArrayMember(idx, true)->Dereference(err);
455   if (err.Fail()) {
456     return result;
457   }
458
459   ConstString name("goid");
460   ValueObjectSP val = g->GetChildMemberWithName(name, true);
461   bool success = false;
462   result.m_goid = val->GetValueAsUnsigned(0, &success);
463   if (!success) {
464     err.SetErrorToGenericError();
465     err.SetErrorString("unable to read goid");
466     return result;
467   }
468   name.SetCString("atomicstatus");
469   val = g->GetChildMemberWithName(name, true);
470   result.m_status = (uint32_t)val->GetValueAsUnsigned(0, &success);
471   if (!success) {
472     err.SetErrorToGenericError();
473     err.SetErrorString("unable to read atomicstatus");
474     return result;
475   }
476   name.SetCString("sched");
477   val = g->GetChildMemberWithName(name, true);
478   result.m_gobuf = val->GetAddressOf(false);
479   name.SetCString("stack");
480   val = g->GetChildMemberWithName(name, true);
481   name.SetCString("lo");
482   ValueObjectSP child = val->GetChildMemberWithName(name, true);
483   result.m_lostack = child->GetValueAsUnsigned(0, &success);
484   if (!success) {
485     err.SetErrorToGenericError();
486     err.SetErrorString("unable to read stack.lo");
487     return result;
488   }
489   name.SetCString("hi");
490   child = val->GetChildMemberWithName(name, true);
491   result.m_histack = child->GetValueAsUnsigned(0, &success);
492   if (!success) {
493     err.SetErrorToGenericError();
494     err.SetErrorString("unable to read stack.hi");
495     return result;
496   }
497   return result;
498 }