Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit a0fc10c

Browse files
committed
The Rust plugin
1 parent 0a642db commit a0fc10c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+9839
-3
lines changed

include/lldb/Expression/ExpressionTypeSystemHelper.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ExpressionTypeSystemHelper {
3232
eKindClangHelper,
3333
eKindSwiftHelper,
3434
eKindGoHelper,
35+
eKindRustHelper,
3536
kNumKinds
3637
};
3738

include/lldb/Expression/ExpressionVariable.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ExpressionVariable
3333
//----------------------------------------------------------------------
3434
// See TypeSystem.h for how to add subclasses to this.
3535
//----------------------------------------------------------------------
36-
enum LLVMCastKind { eKindClang, eKindSwift, eKindGo, kNumKinds };
36+
enum LLVMCastKind { eKindClang, eKindSwift, eKindGo, eKindRust, kNumKinds };
3737

3838
LLVMCastKind getKind() const { return m_kind; }
3939

include/lldb/Symbol/RustASTContext.h

+464
Large diffs are not rendered by default.

include/lldb/Symbol/TypeSystem.h

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class TypeSystem : public PluginInterface {
7373
eKindClang,
7474
eKindSwift,
7575
eKindOCaml,
76+
eKindRust,
7677
kNumKinds
7778
};
7879

include/lldb/lldb-forward.h

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class File;
107107
class FileSpec;
108108
class FileSpecList;
109109
class Flags;
110+
class RustASTContext;
110111
class TypeCategoryImpl;
111112
class FormatManager;
112113
class FormattersMatchCandidate;
@@ -353,6 +354,7 @@ typedef std::shared_ptr<lldb_private::File> FileSP;
353354
typedef std::shared_ptr<lldb_private::Function> FunctionSP;
354355
typedef std::shared_ptr<lldb_private::FunctionCaller> FunctionCallerSP;
355356
typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP;
357+
typedef std::unique_ptr<lldb_private::RustASTContext> RustASTContextUP;
356358
typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;
357359
typedef std::shared_ptr<lldb_private::Instruction> InstructionSP;
358360
typedef std::shared_ptr<lldb_private::InstrumentationRuntime>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Test Rust function calls."""
2+
3+
import os
4+
import time
5+
import unittest2
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
class TestRustExpressions(TestBase):
12+
mydir = TestBase.compute_mydir(__file__)
13+
14+
@add_test_categories(['pyapi'])
15+
@no_debug_info_test
16+
@skipUnlessRustInstalled
17+
def test_with_dsym_and_python_api(self):
18+
"""Test Rust function calls."""
19+
self.buildRust()
20+
self.launchProcess()
21+
self.rust_calls()
22+
23+
def setUp(self):
24+
# Call super's setUp().
25+
TestBase.setUp(self)
26+
# Find the line numbers to break inside main().
27+
self.main_source = "main.rs"
28+
self.break_line = line_number(self.main_source, '// breakpoint')
29+
30+
def launchProcess(self):
31+
exe = os.path.join(os.getcwd(), "main")
32+
33+
target = self.dbg.CreateTarget(exe)
34+
self.assertTrue(target, VALID_TARGET)
35+
36+
bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line)
37+
self.assertTrue(bpt, VALID_BREAKPOINT)
38+
39+
# Now launch the process, and do not stop at entry point.
40+
process = target.LaunchSimple(None, None, self.get_process_working_directory())
41+
42+
self.assertTrue(process, PROCESS_IS_VALID)
43+
44+
# The stop reason of the thread should be breakpoint.
45+
thread_list = lldbutil.get_threads_stopped_at_breakpoint(process, bpt)
46+
47+
# Make sure we stopped at the first breakpoint.
48+
self.assertTrue(
49+
len(thread_list) != 0,
50+
"No thread stopped at our breakpoint.")
51+
self.assertTrue(len(thread_list) == 1,
52+
"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 rust_calls(self):
58+
frame = self.frame()
59+
v = frame.EvaluateExpression("not(true)")
60+
self.assertEqual("(bool) = false", str(v))
61+
v = frame.EvaluateExpression("not(false)")
62+
self.assertEqual("(bool) = true", str(v))
63+
v = frame.EvaluateExpression("constant()")
64+
self.assertEqual("(i64) = -23", str(v))
65+
v = frame.EvaluateExpression("cst2(zzq)")
66+
self.assertEqual("(i16) = -24", str(v))
67+
v = frame.EvaluateExpression("nil()")
68+
self.assertEqual("(()) = {}", str(v))
69+
v = frame.EvaluateExpression("add1(7)")
70+
self.assertEqual("(u32) = 8", str(v))
71+
v = frame.EvaluateExpression("add1d(74.0)")
72+
self.assertEqual("(f64) = 75", str(v))
73+
v = frame.EvaluateExpression("add1s(Struct{field:7}).field")
74+
self.assertEqual("(u8) field = 8", str(v))
75+
v = frame.EvaluateExpression("add1ts(TupleStruct(99)).0")
76+
self.assertEqual("(u8) = 100", str(v))
77+
# v = frame.EvaluateExpression("unifyplus1(SimpleEnum::One{f1:98}).0")
78+
# self.assertEqual("(u16) = 99", str(v))
79+
# v = frame.EvaluateExpression("add1ue(UnivariantEnum::Single(17)).0")
80+
# self.assertEqual("(u8) = 18", str(v))
81+
v = frame.EvaluateExpression("sum(0, 1, 2, 3.0, 4.0)")
82+
self.assertEqual("(f64) = 10", str(v))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#![allow(dead_code)]
2+
#![allow(unused_variables)]
3+
#![allow(unused_assignments)]
4+
5+
fn do_nothing() { }
6+
7+
pub fn not(x: bool) -> bool {
8+
!x
9+
}
10+
11+
pub fn constant() -> i64 {
12+
-23
13+
}
14+
15+
pub fn cst2(x: ()) -> i16 {
16+
-24
17+
}
18+
19+
pub fn nil() -> () {
20+
()
21+
}
22+
23+
pub fn add1(x: u32) -> u32 {
24+
x + 1
25+
}
26+
27+
pub fn add1d(x: f64) -> f64 {
28+
x + 1f64
29+
}
30+
31+
pub struct Struct {
32+
field: u8
33+
}
34+
35+
pub fn add1s(x: Struct) -> Struct {
36+
Struct{field: x.field + 1}
37+
}
38+
39+
pub struct TupleStruct(u8);
40+
41+
pub fn add1ts(x: TupleStruct) -> TupleStruct {
42+
TupleStruct(x.0 + 1)
43+
}
44+
45+
pub enum SimpleEnum {
46+
One{f1: u16},
47+
Two(u16)
48+
}
49+
50+
pub fn unifyplus1(x: SimpleEnum) -> SimpleEnum {
51+
match x {
52+
SimpleEnum::One{f1: v} => SimpleEnum::Two(v + 1),
53+
SimpleEnum::Two(v) => SimpleEnum::Two(v + 1)
54+
}
55+
}
56+
57+
pub enum UnivariantEnum {
58+
Single(u8)
59+
}
60+
61+
pub fn add1ue(x: UnivariantEnum) -> u8 {
62+
match x {
63+
UnivariantEnum::Single(v) => v + 1
64+
}
65+
}
66+
67+
pub fn sum(a: u8, b: u16, c: u32, d: f32, e: f64) -> f64 {
68+
a as f64 + b as f64 + c as f64 + d as f64 + e
69+
}
70+
71+
fn main() {
72+
let a = not(false);
73+
let b = constant();
74+
let zzq = ();
75+
let c = cst2(zzq);
76+
let d = nil();
77+
let e = add1(7);
78+
let f = add1d(7.0);
79+
let g = add1s(Struct{field:8});
80+
let h = add1ts(TupleStruct(72));
81+
let i = unifyplus1(SimpleEnum::Two(11));
82+
let j = add1ue(UnivariantEnum::Single(99));
83+
let k = sum(0, 1, 2, 3.0, 4.0);
84+
85+
do_nothing(); // breakpoint
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
"""Test the Rust expression parser and evaluator."""
2+
3+
import os
4+
import time
5+
import unittest2
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
class TestRustExpressions(TestBase):
12+
mydir = TestBase.compute_mydir(__file__)
13+
14+
@add_test_categories(['pyapi'])
15+
@no_debug_info_test
16+
@skipUnlessRustInstalled
17+
def test_with_dsym_and_python_api(self):
18+
"""Test Rust expression parser and evaluator."""
19+
self.buildRust()
20+
self.launchProcess()
21+
self.rust_expressions()
22+
23+
def setUp(self):
24+
# Call super's setUp().
25+
TestBase.setUp(self)
26+
# Find the line numbers to break inside main().
27+
self.main_source = "main.rs"
28+
self.break_line = line_number(self.main_source, '// breakpoint')
29+
30+
def launchProcess(self):
31+
exe = os.path.join(os.getcwd(), "main")
32+
33+
target = self.dbg.CreateTarget(exe)
34+
self.assertTrue(target, VALID_TARGET)
35+
36+
bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line)
37+
self.assertTrue(bpt, VALID_BREAKPOINT)
38+
39+
# Now launch the process, and do not stop at entry point.
40+
process = target.LaunchSimple(None, None, self.get_process_working_directory())
41+
42+
self.assertTrue(process, PROCESS_IS_VALID)
43+
44+
# The stop reason of the thread should be breakpoint.
45+
thread_list = lldbutil.get_threads_stopped_at_breakpoint(process, bpt)
46+
47+
# Make sure we stopped at the first breakpoint.
48+
self.assertTrue(
49+
len(thread_list) != 0,
50+
"No thread stopped at our breakpoint.")
51+
self.assertTrue(len(thread_list) == 1,
52+
"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 rust_expressions(self):
58+
frame = self.frame()
59+
v = frame.EvaluateExpression("1")
60+
self.assertEqual("(i32) = 1", str(v))
61+
v = frame.EvaluateExpression("1.25")
62+
self.assertEqual("(f64) = 1.25", str(v))
63+
v = frame.EvaluateExpression("1 + 2")
64+
self.assertEqual("(i32) = 3", str(v))
65+
v = frame.EvaluateExpression("+ 2 + - 1")
66+
self.assertEqual("(i32) = 1", str(v))
67+
v = frame.EvaluateExpression("3 + 1 / 4")
68+
self.assertEqual("(i32) = 3", str(v))
69+
v = frame.EvaluateExpression("(3 + 1) / 4")
70+
self.assertEqual("(i32) = 1", str(v))
71+
v = frame.EvaluateExpression("5 % 4")
72+
self.assertEqual("(i32) = 1", str(v))
73+
v = frame.EvaluateExpression("sizeof(4u8)")
74+
self.assertEqual("(usize) = 1", str(v))
75+
v = frame.EvaluateExpression("!0xffu16")
76+
self.assertEqual("(u16) = 65280", str(v))
77+
v = frame.EvaluateExpression("1 << 3")
78+
self.assertEqual("(i32) = 8", str(v))
79+
v = frame.EvaluateExpression("-1 < 3")
80+
self.assertEqual("(bool) = true", str(v))
81+
v = frame.EvaluateExpression("3 <= 3")
82+
self.assertEqual("(bool) = true", str(v))
83+
v = frame.EvaluateExpression("3 >= 3")
84+
self.assertEqual("(bool) = true", str(v))
85+
v = frame.EvaluateExpression("-9 > -11")
86+
self.assertEqual("(bool) = true", str(v))
87+
v = frame.EvaluateExpression("-27 != -17")
88+
self.assertEqual("(bool) = true", str(v))
89+
v = frame.EvaluateExpression("-27 == -17")
90+
self.assertEqual("(bool) = false", str(v))
91+
v = frame.EvaluateExpression("5.0 / 4")
92+
self.assertEqual("(f64) = 1.25", str(v))
93+
v = frame.EvaluateExpression("'c'")
94+
self.assertEqual("(char) = 'c'", str(v))
95+
v = frame.EvaluateExpression("true")
96+
self.assertEqual("(bool) = true", str(v))
97+
v = frame.EvaluateExpression("false")
98+
self.assertEqual("(bool) = false", str(v))
99+
v = frame.EvaluateExpression("!true")
100+
self.assertEqual("(bool) = false", str(v))
101+
v = frame.EvaluateExpression("vstruct.field1")
102+
self.assertEqual("(u8) field1 = 23", str(v))
103+
v = frame.EvaluateExpression("vtuplestruct.0")
104+
self.assertEqual("(u8) = 23", str(v))
105+
v = frame.EvaluateExpression("vtuple.0")
106+
self.assertEqual("(u8) = 23", str(v))
107+
v = frame.EvaluateExpression("vunion.field2")
108+
self.assertEqual("(char) field2 = 'Q'", str(v))
109+
v = frame.EvaluateExpression("vi8array[2]")
110+
self.assertEqual("(i8) [2] = 3", str(v))
111+
v = frame.EvaluateExpression("*vboolpointer")
112+
self.assertEqual("(bool) *vboolpointer = true", str(v))
113+
v = frame.EvaluateExpression("*vcharpointer")
114+
self.assertEqual("(char) *vcharpointer = 'Q'", str(v))
115+
v = frame.EvaluateExpression("*vi8ref")
116+
self.assertEqual("(i8) *vi8ref = -23", str(v))
117+
v = frame.EvaluateExpression("*&vi8")
118+
self.assertEqual("(i8) *&vi8 = -23", str(v))
119+
v = frame.EvaluateExpression("*vu8ref")
120+
self.assertEqual("(u8) *vu8ref = 23", str(v))
121+
v = frame.EvaluateExpression("vsimpleenum", lldb.eDynamicDontRunTarget)
122+
self.assertEqual("(main::SimpleEnum::Two) vsimpleenum = (83, 92)", str(v))
123+
v = frame.EvaluateExpression("vsimpleenum.1")
124+
self.assertEqual("(u16) = 92", str(v))
125+
v = frame.EvaluateExpression("vsimpleenum1.f2")
126+
self.assertEqual("(u8) f2 = 83", str(v))
127+
v = frame.EvaluateExpression("vi8 = 7")
128+
self.assertEqual("(i8) vi8 = 7", str(v))
129+
# Double check.
130+
v = frame.EvaluateExpression("*&vi8")
131+
self.assertEqual("(i8) *&vi8 = 7", str(v))
132+
v = frame.EvaluateExpression("vi8 += 7")
133+
self.assertEqual("(i8) vi8 = 14", str(v))
134+
# Double check.
135+
v = frame.EvaluateExpression("*&vi8")
136+
self.assertEqual("(i8) *&vi8 = 14", str(v))
137+
v = frame.EvaluateExpression("[23i64; 5]")
138+
self.assertEqual("([i64; 5]) = ([0] = 23, [1] = 23, [2] = 23, [3] = 23, [4] = 23)", str(v))
139+
v = frame.EvaluateExpression("23 as u8")
140+
self.assertEqual("(u8) = 23", str(v))
141+
v = frame.EvaluateExpression('b"hi"')
142+
self.assertEqual("([u8; 2]) * = ([0] = 104, [1] = 105)", str(v))
143+
# FIXME need pretty-printing for &str
144+
# v = frame.EvaluateExpression('"hi"')
145+
# self.assertEqual("fixme", str(v))
146+
v = frame.EvaluateExpression("Struct { field1: 8, field2: 'c'}")
147+
self.assertEqual("(main::Struct) * = (field1 = 8, field2 = 'c')", str(v))
148+
v = frame.EvaluateExpression("Struct { field1: 8, .. vstruct}")
149+
self.assertEqual("(main::Struct) * = (field1 = 8, field2 = 'Q')", str(v))
150+
v = frame.EvaluateExpression("TupleStruct(24, 'R')")
151+
self.assertEqual("(main::TupleStruct) * = (24, 'R')", str(v))
152+
v = frame.EvaluateExpression("0..5")
153+
self.assertEqual("(core::ops::range::Range<i32>) * = (start = 0, end = 5)", str(v))
154+
# v = frame.EvaluateExpression("0..=5")
155+
# self.assertEqual("(core::ops::range::RangeInclusive<i32>) * = (start = 0, end = 5)", str(v))
156+
v = frame.EvaluateExpression("..5")
157+
self.assertEqual("(core::ops::range::RangeTo<i32>) * = (end = 5)", str(v))
158+
# v = frame.EvaluateExpression("..=5")
159+
# self.assertEqual("(core::ops::range::RangeToInclusive<i32> * = (end = 5)", str(v))
160+
v = frame.EvaluateExpression("0..")
161+
self.assertEqual("(core::ops::range::RangeFrom<i32>) * = (start = 0)", str(v))
162+
# Can't allocate a zero-length object
163+
# v = frame.EvaluateExpression("..")
164+
# self.assertEqual("(core::ops::range::RangeFull) * = ()", str(v))

0 commit comments

Comments
 (0)