aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp
blob: c52fc1e121d88c1929d789036111c8bb71e116d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//===-- GoLanguageRuntime.cpp --------------------------------------*- C++
//-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "GoLanguageRuntime.h"

#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Error.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/Twine.h"

#include <vector>

using namespace lldb;
using namespace lldb_private;

namespace {
ValueObjectSP GetChild(ValueObject &obj, const char *name,
                       bool dereference = true) {
  ConstString name_const_str(name);
  ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true);
  if (dereference && result && result->IsPointerType()) {
    Error err;
    result = result->Dereference(err);
    if (err.Fail())
      result.reset();
  }
  return result;
}

ConstString ReadString(ValueObject &str, Process *process) {
  ConstString result;
  ValueObjectSP data = GetChild(str, "str", false);
  ValueObjectSP len = GetChild(str, "len");
  if (len && data) {
    Error err;
    lldb::addr_t addr = data->GetPointerValue();
    if (addr == LLDB_INVALID_ADDRESS)
      return result;
    uint64_t byte_size = len->GetValueAsUnsigned(0);
    char *buf = new char[byte_size + 1];
    buf[byte_size] = 0;
    size_t bytes_read = process->ReadMemory(addr, buf, byte_size, err);
    if (!(err.Fail() || bytes_read != byte_size))
      result = ConstString(buf, bytes_read);
    delete[] buf;
  }
  return result;
}

ConstString ReadTypeName(ValueObjectSP type, Process *process) {
  if (ValueObjectSP uncommon = GetChild(*type, "x")) {
    ValueObjectSP name = GetChild(*uncommon, "name");
    ValueObjectSP package = GetChild(*uncommon, "pkgpath");
    if (name && name->GetPointerValue() != 0 && package &&
        package->GetPointerValue() != 0) {
      ConstString package_const_str = ReadString(*package, process);
      ConstString name_const_str = ReadString(*name, process);
      if (package_const_str.GetLength() == 0)
        return name_const_str;
      return ConstString((package_const_str.GetStringRef() + "." +
                          name_const_str.GetStringRef())
                             .str());
    }
  }
  ValueObjectSP name = GetChild(*type, "_string");
  if (name)
    return ReadString(*name, process);
  return ConstString("");
}

CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx,
                               bool *is_direct) {
  uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0);
  *is_direct = GoASTContext::IsDirectIface(kind);
  if (GoASTContext::IsPointerKind(kind)) {
    CompilerType type_ptr = type->GetCompilerType().GetPointerType();
    Error err;
    ValueObjectSP elem =
        type->CreateValueObjectFromAddress("elem", type->GetAddressOf() +
                                                       type->GetByteSize(),
                                           *exe_ctx, type_ptr)
            ->Dereference(err);
    if (err.Fail())
      return CompilerType();
    bool tmp_direct;
    return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType();
  }
  Target *target = exe_ctx->GetTargetPtr();
  Process *process = exe_ctx->GetProcessPtr();

  ConstString const_typename = ReadTypeName(type, process);
  if (const_typename.GetLength() == 0)
    return CompilerType();

  SymbolContext sc;
  TypeList type_list;
  llvm::DenseSet<SymbolFile *> searched_symbol_files;
  uint32_t num_matches = target->GetImages().FindTypes(
      sc, const_typename, false, 2, searched_symbol_files, type_list);
  if (num_matches > 0) {
    return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
  }
  return CompilerType();
}
}

bool GoLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
  return GoASTContext::IsGoInterface(in_value.GetCompilerType());
}

bool GoLanguageRuntime::GetDynamicTypeAndAddress(
    ValueObject &in_value, lldb::DynamicValueType use_dynamic,
    TypeAndOrName &class_type_or_name, Address &dynamic_address,
    Value::ValueType &value_type) {
  value_type = Value::eValueTypeScalar;
  class_type_or_name.Clear();
  if (CouldHaveDynamicValue(in_value)) {
    Error err;
    ValueObjectSP iface = in_value.GetStaticValue();
    ValueObjectSP data_sp = GetChild(*iface, "data", false);
    if (!data_sp)
      return false;

    if (ValueObjectSP tab = GetChild(*iface, "tab"))
      iface = tab;
    ValueObjectSP type = GetChild(*iface, "_type");
    if (!type) {
      return false;
    }

    bool direct;
    ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
    CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct);
    if (!final_type)
      return false;
    if (direct) {
      class_type_or_name.SetCompilerType(final_type);
    } else {
      // TODO: implement reference types or fix caller to support dynamic types
      // that aren't pointers
      // so we don't have to introduce this extra pointer.
      class_type_or_name.SetCompilerType(final_type.GetPointerType());
    }

    dynamic_address.SetLoadAddress(data_sp->GetPointerValue(),
                                   exe_ctx.GetTargetPtr());

    return true;
  }
  return false;
}

TypeAndOrName
GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
                                    ValueObject &static_value) {
  return type_and_or_name;
}

//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
LanguageRuntime *
GoLanguageRuntime::CreateInstance(Process *process,
                                  lldb::LanguageType language) {
  if (language == eLanguageTypeGo)
    return new GoLanguageRuntime(process);
  else
    return NULL;
}

void GoLanguageRuntime::Initialize() {
  PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language Runtime",
                                CreateInstance);
}

void GoLanguageRuntime::Terminate() {
  PluginManager::UnregisterPlugin(CreateInstance);
}

lldb_private::ConstString GoLanguageRuntime::GetPluginNameStatic() {
  static ConstString g_name("golang");
  return g_name;
}

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GoLanguageRuntime::GetPluginName() {
  return GetPluginNameStatic();
}

uint32_t GoLanguageRuntime::GetPluginVersion() { return 1; }