Skip to content

Commit 2b56f86

Browse files
author
Ryan Brown
committedOct 6, 2015
Add missing GoLanguageRuntime files.
llvm-svn: 249459
1 parent 05e9cb5 commit 2b56f86

File tree

6 files changed

+467
-0
lines changed

6 files changed

+467
-0
lines changed
 
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
set(LLVM_NO_RTTI 1)
2+
3+
add_lldb_library(lldbPluginLanguageRuntimeGo
4+
GoLanguageRuntime.cpp
5+
)
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
//===-- GoLanguageRuntime.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 "GoLanguageRuntime.h"
11+
12+
#include "lldb/Breakpoint/BreakpointLocation.h"
13+
#include "lldb/Core/ConstString.h"
14+
#include "lldb/Core/Error.h"
15+
#include "lldb/Core/Log.h"
16+
#include "lldb/Core/Module.h"
17+
#include "lldb/Core/PluginManager.h"
18+
#include "lldb/Core/Scalar.h"
19+
#include "lldb/Core/ValueObject.h"
20+
#include "lldb/Core/ValueObjectMemory.h"
21+
#include "lldb/Symbol/GoASTContext.h"
22+
#include "lldb/Symbol/Symbol.h"
23+
#include "lldb/Symbol/TypeList.h"
24+
#include "lldb/Target/Process.h"
25+
#include "lldb/Target/RegisterContext.h"
26+
#include "lldb/Target/SectionLoadList.h"
27+
#include "lldb/Target/StopInfo.h"
28+
#include "lldb/Target/Target.h"
29+
#include "lldb/Target/Thread.h"
30+
#include "llvm/ADT/Twine.h"
31+
32+
#include <vector>
33+
34+
using namespace lldb;
35+
using namespace lldb_private;
36+
37+
namespace {
38+
ValueObjectSP GetChild(ValueObject& obj, const char* name, bool dereference = true) {
39+
ConstString name_const_str(name);
40+
ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true);
41+
if (dereference && result && result->IsPointerType()) {
42+
Error err;
43+
result = result->Dereference(err);
44+
if (err.Fail())
45+
result.reset();
46+
}
47+
return result;
48+
}
49+
50+
ConstString ReadString(ValueObject& str, Process* process) {
51+
ConstString result;
52+
ValueObjectSP data = GetChild(str, "str", false);
53+
ValueObjectSP len = GetChild(str, "len");
54+
if (len && data)
55+
{
56+
Error err;
57+
lldb::addr_t addr = data->GetPointerValue();
58+
if (addr == LLDB_INVALID_ADDRESS)
59+
return result;
60+
uint64_t byte_size = len->GetValueAsUnsigned(0);
61+
char* buf = new char[byte_size + 1];
62+
buf[byte_size] = 0;
63+
size_t bytes_read = process->ReadMemory (addr,
64+
buf,
65+
byte_size,
66+
err);
67+
if (!(err.Fail() || bytes_read != byte_size))
68+
result = ConstString(buf, bytes_read);
69+
delete[] buf;
70+
}
71+
return result;
72+
}
73+
74+
ConstString
75+
ReadTypeName(ValueObjectSP type, Process* process)
76+
{
77+
if (ValueObjectSP uncommon = GetChild(*type, "x"))
78+
{
79+
ValueObjectSP name = GetChild(*uncommon, "name");
80+
ValueObjectSP package = GetChild(*uncommon, "pkgpath");
81+
if (name && name->GetPointerValue() != 0 && package && package->GetPointerValue() != 0)
82+
{
83+
ConstString package_const_str = ReadString(*package, process);
84+
ConstString name_const_str = ReadString(*name, process);
85+
if (package_const_str.GetLength() == 0)
86+
return name_const_str;
87+
return ConstString((package_const_str.GetStringRef() + "." + name_const_str.GetStringRef()).str());
88+
}
89+
}
90+
ValueObjectSP name = GetChild(*type, "_string");
91+
if (name)
92+
return ReadString(*name, process);
93+
return ConstString("");
94+
}
95+
96+
CompilerType
97+
LookupRuntimeType(ValueObjectSP type, ExecutionContext* exe_ctx, bool* is_direct)
98+
{
99+
uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0);
100+
*is_direct = GoASTContext::IsDirectIface(kind);
101+
if (GoASTContext::IsPointerKind(kind))
102+
{
103+
CompilerType type_ptr = type->GetCompilerType().GetPointerType();
104+
Error err;
105+
ValueObjectSP elem = type->CreateValueObjectFromAddress("elem", type->GetAddressOf() + type->GetByteSize(), *exe_ctx, type_ptr)->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+
uint32_t num_matches = target->GetImages().FindTypes (sc,
121+
const_typename,
122+
false,
123+
2,
124+
type_list);
125+
if (num_matches > 0) {
126+
return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
127+
}
128+
return CompilerType();
129+
}
130+
131+
}
132+
133+
bool
134+
GoLanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
135+
{
136+
return GoASTContext::IsGoInterface(in_value.GetCompilerType());
137+
}
138+
139+
bool
140+
GoLanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
141+
TypeAndOrName &class_type_or_name, Address &dynamic_address,
142+
Value::ValueType &value_type)
143+
{
144+
value_type = Value::eValueTypeScalar;
145+
class_type_or_name.Clear();
146+
if (CouldHaveDynamicValue (in_value))
147+
{
148+
Error err;
149+
ValueObjectSP iface = in_value.GetStaticValue();
150+
ValueObjectSP data_sp = GetChild(*iface, "data", false);
151+
if (!data_sp)
152+
return false;
153+
154+
if (ValueObjectSP tab = GetChild(*iface, "tab"))
155+
iface = tab;
156+
ValueObjectSP type = GetChild(*iface, "_type");
157+
if (!type)
158+
{
159+
return false;
160+
}
161+
162+
bool direct;
163+
ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
164+
CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct);
165+
if (!final_type)
166+
return false;
167+
if (direct)
168+
{
169+
class_type_or_name.SetCompilerType(final_type);
170+
}
171+
else
172+
{
173+
// TODO: implement reference types or fix caller to support dynamic types that aren't pointers
174+
// so we don't have to introduce this extra pointer.
175+
class_type_or_name.SetCompilerType(final_type.GetPointerType());
176+
}
177+
178+
dynamic_address.SetLoadAddress(data_sp->GetPointerValue(), exe_ctx.GetTargetPtr());
179+
180+
return true;
181+
}
182+
return false;
183+
}
184+
185+
TypeAndOrName
186+
GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value)
187+
{
188+
return type_and_or_name;
189+
}
190+
191+
//------------------------------------------------------------------
192+
// Static Functions
193+
//------------------------------------------------------------------
194+
LanguageRuntime *
195+
GoLanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language)
196+
{
197+
if (language == eLanguageTypeGo)
198+
return new GoLanguageRuntime (process);
199+
else
200+
return NULL;
201+
}
202+
203+
void
204+
GoLanguageRuntime::Initialize()
205+
{
206+
PluginManager::RegisterPlugin (GetPluginNameStatic(),
207+
"Go Language Runtime",
208+
CreateInstance);
209+
}
210+
211+
void
212+
GoLanguageRuntime::Terminate()
213+
{
214+
PluginManager::UnregisterPlugin (CreateInstance);
215+
}
216+
217+
lldb_private::ConstString
218+
GoLanguageRuntime::GetPluginNameStatic()
219+
{
220+
static ConstString g_name("golang");
221+
return g_name;
222+
}
223+
224+
//------------------------------------------------------------------
225+
// PluginInterface protocol
226+
//------------------------------------------------------------------
227+
lldb_private::ConstString
228+
GoLanguageRuntime::GetPluginName()
229+
{
230+
return GetPluginNameStatic();
231+
}
232+
233+
uint32_t
234+
GoLanguageRuntime::GetPluginVersion()
235+
{
236+
return 1;
237+
}
238+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===-- GoLanguageRuntime.h ----------------------------------------*- 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+
#ifndef liblldb_GoLanguageRuntime_h_
11+
#define liblldb_GoLanguageRuntime_h_
12+
13+
// C Includes
14+
// C++ Includes
15+
// Other libraries and framework includes
16+
// Project includes
17+
#include "lldb/lldb-private.h"
18+
#include "lldb/Breakpoint/BreakpointResolver.h"
19+
#include "lldb/Target/LanguageRuntime.h"
20+
#include "lldb/Core/Value.h"
21+
22+
namespace lldb_private {
23+
24+
class GoLanguageRuntime :
25+
public lldb_private::LanguageRuntime
26+
{
27+
public:
28+
~GoLanguageRuntime() { }
29+
30+
lldb::LanguageType
31+
GetLanguageType() const override
32+
{
33+
return lldb::eLanguageTypeGo;
34+
}
35+
36+
bool
37+
GetObjectDescription(Stream &str, ValueObject &object) override
38+
{
39+
// TODO(ribrdb): Maybe call String() method?
40+
return false;
41+
}
42+
43+
bool
44+
GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override
45+
{
46+
return false;
47+
}
48+
49+
bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
50+
TypeAndOrName &class_type_or_name, Address &address,
51+
Value::ValueType &value_type) override;
52+
53+
bool CouldHaveDynamicValue(ValueObject &in_value) override;
54+
55+
lldb::BreakpointResolverSP
56+
CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override
57+
{
58+
return lldb::BreakpointResolverSP();
59+
}
60+
61+
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) override;
62+
63+
//------------------------------------------------------------------
64+
// Static Functions
65+
//------------------------------------------------------------------
66+
static void
67+
Initialize();
68+
69+
static void
70+
Terminate();
71+
72+
static lldb_private::LanguageRuntime *
73+
CreateInstance (Process *process, lldb::LanguageType language);
74+
75+
static lldb_private::ConstString
76+
GetPluginNameStatic();
77+
78+
//------------------------------------------------------------------
79+
// PluginInterface protocol
80+
//------------------------------------------------------------------
81+
virtual lldb_private::ConstString
82+
GetPluginName();
83+
84+
virtual uint32_t
85+
GetPluginVersion();
86+
87+
private:
88+
GoLanguageRuntime(Process *process) : lldb_private::LanguageRuntime(process) { } // Call CreateInstance instead.
89+
};
90+
91+
} // namespace lldb_private
92+
93+
#endif // liblldb_GoLanguageRuntime_h_
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
##===- Source/Plugins/LangRuntime/Go/Makefile ----*- Makefile -*-===##
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+
LLDB_LEVEL := ../../../..
11+
LIBRARYNAME := lldbPluginLanguageRuntimeGo
12+
BUILD_ARCHIVE = 1
13+
14+
include $(LLDB_LEVEL)/Makefile
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"""Test the go dynamic type handling."""
2+
3+
import os, time
4+
import unittest2
5+
import lldb
6+
import lldbutil
7+
from lldbtest import *
8+
9+
class TestGoLanguageRuntime(TestBase):
10+
11+
mydir = TestBase.compute_mydir(__file__)
12+
13+
@python_api_test
14+
@skipIfRemote # Not remote test suite ready
15+
@skipUnlessGoInstalled
16+
def test_with_dsym_and_python_api(self):
17+
"""Test GoASTContext dwarf parsing."""
18+
self.buildGo()
19+
self.launchProcess()
20+
self.go_interface_types()
21+
22+
def setUp(self):
23+
# Call super's setUp().
24+
TestBase.setUp(self)
25+
# Find the line numbers to break inside main().
26+
self.main_source = "main.go"
27+
self.break_line1 = line_number(self.main_source, '// Set breakpoint 1')
28+
self.break_line2 = line_number(self.main_source, '// Set breakpoint 2')
29+
30+
31+
def launchProcess(self):
32+
exe = os.path.join(os.getcwd(), "a.out")
33+
34+
target = self.dbg.CreateTarget(exe)
35+
self.assertTrue(target, VALID_TARGET)
36+
37+
bpt1 = target.BreakpointCreateByLocation(self.main_source, self.break_line1)
38+
self.assertTrue(bpt1, VALID_BREAKPOINT)
39+
bpt2 = target.BreakpointCreateByLocation(self.main_source, self.break_line2)
40+
self.assertTrue(bpt2, VALID_BREAKPOINT)
41+
42+
# Now launch the process, and do not stop at entry point.
43+
process = target.LaunchSimple (None, None, self.get_process_working_directory())
44+
45+
self.assertTrue(process, PROCESS_IS_VALID)
46+
47+
# The stop reason of the thread should be breakpoint.
48+
thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, bpt1)
49+
50+
# Make sure we stopped at the first breakpoint.
51+
self.assertTrue (len(thread_list) != 0, "No thread stopped at our breakpoint.")
52+
self.assertTrue (len(thread_list) == 1, "More than one thread stopped at our breakpoint.")
53+
54+
frame = thread_list[0].GetFrameAtIndex(0)
55+
self.assertTrue (frame, "Got a valid frame 0 frame.")
56+
57+
def go_interface_types(self):
58+
f = self.frame()
59+
v = f.FindVariable("a", lldb.eDynamicCanRunTarget)
60+
self.assertEqual("*int", v.GetType().name)
61+
self.assertEqual(1, v.Dereference().GetValueAsSigned())
62+
v = f.FindVariable("b", lldb.eDynamicCanRunTarget)
63+
self.assertEqual("*float64", v.GetType().name)
64+
err = lldb.SBError()
65+
self.assertEqual(2.0, v.Dereference().GetData().GetDouble(err, 0))
66+
v = f.FindVariable("c", lldb.eDynamicCanRunTarget)
67+
self.assertEqual("*main.SomeFooer", v.GetType().name)
68+
self.assertEqual(9, v.Dereference().GetChildAtIndex(0).GetValueAsSigned())
69+
v = f.FindVariable("d", lldb.eDynamicCanRunTarget)
70+
self.assertEqual("*main.AnotherFooer", v.GetType().name)
71+
self.assertEqual(-1, v.Dereference().GetChildAtIndex(0).GetValueAsSigned())
72+
self.assertEqual(-2, v.Dereference().GetChildAtIndex(1).GetValueAsSigned())
73+
self.assertEqual(-3, v.Dereference().GetChildAtIndex(2).GetValueAsSigned())
74+
75+
if __name__ == '__main__':
76+
import atexit
77+
lldb.SBDebugger.Initialize()
78+
atexit.register(lambda: lldb.SBDebugger.Terminate())
79+
unittest2.main()

‎lldb/test/lang/go/runtime/main.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type Fooer interface {
6+
Foo() int
7+
}
8+
9+
type SomeFooer struct {
10+
val int
11+
}
12+
13+
func (s SomeFooer) Foo() int {
14+
return s.val
15+
}
16+
17+
type AnotherFooer struct {
18+
a, b, c int
19+
}
20+
21+
func (s AnotherFooer) Foo() int {
22+
return s.a
23+
}
24+
25+
26+
func printEface(a, b, c, d interface{}) {
27+
fmt.Println(a, b, c, d) // Set breakpoint 1
28+
}
29+
30+
func printIface(a, b Fooer) {
31+
fmt.Println(a, b) // Set breakpoint 2
32+
}
33+
func main() {
34+
sf := SomeFooer{9}
35+
af := AnotherFooer{-1, -2, -3}
36+
printEface(1,2.0, sf, af)
37+
printIface(sf, af)
38+
}

0 commit comments

Comments
 (0)
Please sign in to comment.