]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp
MFV r337744:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / LanguageRuntime / Go / GoLanguageRuntime.cpp
1 //===-- GoLanguageRuntime.cpp --------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "GoLanguageRuntime.h"
12
13 #include "lldb/Breakpoint/BreakpointLocation.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/Scalar.h"
17 #include "lldb/Core/ValueObject.h"
18 #include "lldb/Core/ValueObjectMemory.h"
19 #include "lldb/Symbol/GoASTContext.h"
20 #include "lldb/Symbol/Symbol.h"
21 #include "lldb/Symbol/SymbolFile.h"
22 #include "lldb/Symbol/TypeList.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/SectionLoadList.h"
26 #include "lldb/Target/StopInfo.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/Thread.h"
29 #include "lldb/Utility/ConstString.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/Status.h"
32 #include "llvm/ADT/Twine.h"
33
34 #include <vector>
35
36 using namespace lldb;
37 using namespace lldb_private;
38
39 namespace {
40 ValueObjectSP GetChild(ValueObject &obj, const char *name,
41                        bool dereference = true) {
42   ConstString name_const_str(name);
43   ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true);
44   if (dereference && result && result->IsPointerType()) {
45     Status err;
46     result = result->Dereference(err);
47     if (err.Fail())
48       result.reset();
49   }
50   return result;
51 }
52
53 ConstString ReadString(ValueObject &str, Process *process) {
54   ConstString result;
55   ValueObjectSP data = GetChild(str, "str", false);
56   ValueObjectSP len = GetChild(str, "len");
57   if (len && data) {
58     Status err;
59     lldb::addr_t addr = data->GetPointerValue();
60     if (addr == LLDB_INVALID_ADDRESS)
61       return result;
62     uint64_t byte_size = len->GetValueAsUnsigned(0);
63     char *buf = new char[byte_size + 1];
64     buf[byte_size] = 0;
65     size_t bytes_read = process->ReadMemory(addr, buf, byte_size, err);
66     if (!(err.Fail() || bytes_read != byte_size))
67       result = ConstString(buf, bytes_read);
68     delete[] buf;
69   }
70   return result;
71 }
72
73 ConstString ReadTypeName(ValueObjectSP type, Process *process) {
74   if (ValueObjectSP uncommon = GetChild(*type, "x")) {
75     ValueObjectSP name = GetChild(*uncommon, "name");
76     ValueObjectSP package = GetChild(*uncommon, "pkgpath");
77     if (name && name->GetPointerValue() != 0 && package &&
78         package->GetPointerValue() != 0) {
79       ConstString package_const_str = ReadString(*package, process);
80       ConstString name_const_str = ReadString(*name, process);
81       if (package_const_str.GetLength() == 0)
82         return name_const_str;
83       return ConstString((package_const_str.GetStringRef() + "." +
84                           name_const_str.GetStringRef())
85                              .str());
86     }
87   }
88   ValueObjectSP name = GetChild(*type, "_string");
89   if (name)
90     return ReadString(*name, process);
91   return ConstString("");
92 }
93
94 CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx,
95                                bool *is_direct) {
96   uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0);
97   *is_direct = GoASTContext::IsDirectIface(kind);
98   if (GoASTContext::IsPointerKind(kind)) {
99     CompilerType type_ptr = type->GetCompilerType().GetPointerType();
100     Status err;
101     ValueObjectSP elem =
102         type->CreateValueObjectFromAddress("elem", type->GetAddressOf() +
103                                                        type->GetByteSize(),
104                                            *exe_ctx, type_ptr)
105             ->Dereference(err);
106     if (err.Fail())
107       return CompilerType();
108     bool tmp_direct;
109     return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType();
110   }
111   Target *target = exe_ctx->GetTargetPtr();
112   Process *process = exe_ctx->GetProcessPtr();
113
114   ConstString const_typename = ReadTypeName(type, process);
115   if (const_typename.GetLength() == 0)
116     return CompilerType();
117
118   SymbolContext sc;
119   TypeList type_list;
120   llvm::DenseSet<SymbolFile *> searched_symbol_files;
121   uint32_t num_matches = target->GetImages().FindTypes(
122       sc, const_typename, false, 2, searched_symbol_files, type_list);
123   if (num_matches > 0) {
124     return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
125   }
126   return CompilerType();
127 }
128 }
129
130 bool GoLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
131   return GoASTContext::IsGoInterface(in_value.GetCompilerType());
132 }
133
134 bool GoLanguageRuntime::GetDynamicTypeAndAddress(
135     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
136     TypeAndOrName &class_type_or_name, Address &dynamic_address,
137     Value::ValueType &value_type) {
138   value_type = Value::eValueTypeScalar;
139   class_type_or_name.Clear();
140   if (CouldHaveDynamicValue(in_value)) {
141     Status err;
142     ValueObjectSP iface = in_value.GetStaticValue();
143     ValueObjectSP data_sp = GetChild(*iface, "data", false);
144     if (!data_sp)
145       return false;
146
147     if (ValueObjectSP tab = GetChild(*iface, "tab"))
148       iface = tab;
149     ValueObjectSP type = GetChild(*iface, "_type");
150     if (!type) {
151       return false;
152     }
153
154     bool direct;
155     ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
156     CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct);
157     if (!final_type)
158       return false;
159     if (direct) {
160       class_type_or_name.SetCompilerType(final_type);
161     } else {
162       // TODO: implement reference types or fix caller to support dynamic types
163       // that aren't pointers
164       // so we don't have to introduce this extra pointer.
165       class_type_or_name.SetCompilerType(final_type.GetPointerType());
166     }
167
168     dynamic_address.SetLoadAddress(data_sp->GetPointerValue(),
169                                    exe_ctx.GetTargetPtr());
170
171     return true;
172   }
173   return false;
174 }
175
176 TypeAndOrName
177 GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
178                                     ValueObject &static_value) {
179   return type_and_or_name;
180 }
181
182 //------------------------------------------------------------------
183 // Static Functions
184 //------------------------------------------------------------------
185 LanguageRuntime *
186 GoLanguageRuntime::CreateInstance(Process *process,
187                                   lldb::LanguageType language) {
188   if (language == eLanguageTypeGo)
189     return new GoLanguageRuntime(process);
190   else
191     return NULL;
192 }
193
194 void GoLanguageRuntime::Initialize() {
195   PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language Runtime",
196                                 CreateInstance);
197 }
198
199 void GoLanguageRuntime::Terminate() {
200   PluginManager::UnregisterPlugin(CreateInstance);
201 }
202
203 lldb_private::ConstString GoLanguageRuntime::GetPluginNameStatic() {
204   static ConstString g_name("golang");
205   return g_name;
206 }
207
208 //------------------------------------------------------------------
209 // PluginInterface protocol
210 //------------------------------------------------------------------
211 lldb_private::ConstString GoLanguageRuntime::GetPluginName() {
212   return GetPluginNameStatic();
213 }
214
215 uint32_t GoLanguageRuntime::GetPluginVersion() { return 1; }