1 | #include "DataFormatters/FormatterBytecode.h" |
2 | #include "lldb/Utility/StreamString.h" |
3 | |
4 | #include "gtest/gtest.h" |
5 | |
6 | using namespace lldb_private; |
7 | using namespace lldb; |
8 | using namespace FormatterBytecode; |
9 | using llvm::StringRef; |
10 | |
11 | namespace { |
12 | class FormatterBytecodeTest : public ::testing::Test {}; |
13 | |
14 | bool Interpret(std::vector<uint8_t> code, DataStack &data) { |
15 | auto buf = |
16 | StringRef(reinterpret_cast<const char *>(code.data()), code.size()); |
17 | std::vector<ControlStackElement> control({buf}); |
18 | if (auto error = Interpret(control, data, sel: sel_summary)) { |
19 | #ifndef NDEBUG |
20 | llvm::errs() << llvm::toString(E: std::move(error)) << '\n'; |
21 | #else |
22 | llvm::consumeError(std::move(error)); |
23 | #endif |
24 | return false; |
25 | } |
26 | return true; |
27 | } |
28 | |
29 | } // namespace |
30 | |
31 | TEST_F(FormatterBytecodeTest, StackOps) { |
32 | { |
33 | DataStack data; |
34 | ASSERT_TRUE(Interpret({op_lit_uint, 23, op_dup, op_plus}, data)); |
35 | ASSERT_EQ(data.Pop<uint64_t>(), 46u); |
36 | } |
37 | { |
38 | DataStack data; |
39 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_drop}, data)); |
40 | ASSERT_EQ(data.size(), 0u); |
41 | } |
42 | { |
43 | for (unsigned char i = 0; i < 3; ++i) { |
44 | DataStack data; |
45 | |
46 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_lit_uint, 2, |
47 | op_lit_uint, i, op_pick}, |
48 | data)); |
49 | ASSERT_EQ(data.Pop<uint64_t>(), i); |
50 | } |
51 | } |
52 | { |
53 | DataStack data; |
54 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_over}, data)); |
55 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
56 | } |
57 | { |
58 | DataStack data; |
59 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_swap}, data)); |
60 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
61 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
62 | } |
63 | { |
64 | DataStack data; |
65 | ASSERT_TRUE(Interpret( |
66 | {op_lit_uint, 0, op_lit_uint, 1, op_lit_uint, 2, op_rot}, data)); |
67 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
68 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
69 | ASSERT_EQ(data.Pop<uint64_t>(), 2u); |
70 | } |
71 | } |
72 | |
73 | TEST_F(FormatterBytecodeTest, ControlOps) { |
74 | { |
75 | DataStack data; |
76 | ASSERT_TRUE( |
77 | Interpret({op_lit_uint, 0, op_begin, 2, op_lit_uint, 42, op_if}, data)); |
78 | ASSERT_EQ(data.size(), 0u); |
79 | } |
80 | { |
81 | DataStack data; |
82 | ASSERT_TRUE( |
83 | Interpret({op_lit_uint, 1, op_begin, 2, op_lit_uint, 42, op_if}, data)); |
84 | ASSERT_EQ(data.Pop<uint64_t>(), 42u); |
85 | } |
86 | { |
87 | DataStack data; |
88 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_begin, 2, op_lit_uint, 42, |
89 | op_begin, 2, op_lit_uint, 23, op_ifelse}, |
90 | data)); |
91 | ASSERT_EQ(data.Pop<uint64_t>(), 23u); |
92 | } |
93 | { |
94 | DataStack data; |
95 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_begin, 2, op_lit_uint, 42, |
96 | op_begin, 2, op_lit_uint, 23, op_ifelse}, |
97 | data)); |
98 | ASSERT_EQ(data.Pop<uint64_t>(), 42u); |
99 | } |
100 | { |
101 | DataStack data; |
102 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_begin, 3, op_lit_uint, 42, |
103 | op_return, op_if, op_lit_uint, 23}, |
104 | data)); |
105 | ASSERT_EQ(data.Pop<uint64_t>(), 42u); |
106 | } |
107 | } |
108 | |
109 | TEST_F(FormatterBytecodeTest, ConversionOps) { |
110 | { |
111 | DataStack data(lldb::ValueObjectSP{}); |
112 | ASSERT_TRUE(Interpret({op_is_null}, data)); |
113 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
114 | } |
115 | { |
116 | DataStack data; |
117 | ASSERT_TRUE(Interpret({op_lit_uint, 1u, op_as_int}, data)); |
118 | ASSERT_EQ(data.Pop<int64_t>(), 1); |
119 | } |
120 | { |
121 | DataStack data; |
122 | ASSERT_TRUE(Interpret({op_lit_int, 126, op_as_uint}, data)); |
123 | ASSERT_EQ(data.Pop<uint64_t>(), ~1ULL); |
124 | } |
125 | } |
126 | |
127 | TEST_F(FormatterBytecodeTest, ArithOps) { |
128 | { |
129 | DataStack data; |
130 | ASSERT_TRUE(Interpret({op_lit_uint, 2, op_lit_uint, 3, op_plus}, data)); |
131 | ASSERT_EQ(data.Pop<uint64_t>(), 5u); |
132 | } |
133 | { |
134 | DataStack data; |
135 | ASSERT_TRUE(Interpret({op_lit_uint, 3, op_lit_uint, 2, op_minus}, data)); |
136 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
137 | } |
138 | { |
139 | DataStack data; |
140 | ASSERT_TRUE(Interpret({op_lit_uint, 3, op_lit_uint, 2, op_mul}, data)); |
141 | ASSERT_EQ(data.Pop<uint64_t>(), 6u); |
142 | } |
143 | { |
144 | DataStack data; |
145 | ASSERT_TRUE(Interpret({op_lit_uint, 6, op_lit_uint, 2, op_div}, data)); |
146 | ASSERT_EQ(data.Pop<uint64_t>(), 3u); |
147 | } |
148 | { |
149 | DataStack data; |
150 | ASSERT_FALSE(Interpret({op_lit_uint, 23, op_lit_uint, 0, op_div}, data)); |
151 | } |
152 | { |
153 | DataStack data; |
154 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 2, op_shl}, data)); |
155 | ASSERT_EQ(data.Pop<uint64_t>(), 4u); |
156 | } |
157 | { |
158 | DataStack data; |
159 | unsigned char minus_one = 127; |
160 | ASSERT_FALSE( |
161 | Interpret({op_lit_int, minus_one, op_lit_uint, 2, op_shl}, data)); |
162 | unsigned char minus_two = 126; |
163 | ASSERT_TRUE( |
164 | Interpret({op_lit_int, minus_two, op_lit_uint, 1, op_shr}, data)); |
165 | ASSERT_EQ(data.Pop<int64_t>(), -1); |
166 | } |
167 | { |
168 | DataStack data; |
169 | ASSERT_FALSE(Interpret({op_lit_uint, 1, op_lit_uint, 65, op_shl}, data)); |
170 | ASSERT_FALSE(Interpret({op_lit_uint, 1, op_lit_uint, 65, op_shr}, data)); |
171 | } |
172 | { |
173 | DataStack data; |
174 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_and}, data)); |
175 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
176 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_and}, data)); |
177 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
178 | } |
179 | { |
180 | DataStack data; |
181 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_or}, data)); |
182 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
183 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_or}, data)); |
184 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
185 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_or}, data)); |
186 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
187 | } |
188 | { |
189 | DataStack data; |
190 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_xor}, data)); |
191 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
192 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_xor}, data)); |
193 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
194 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_xor}, data)); |
195 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
196 | } |
197 | { |
198 | DataStack data; |
199 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_not}, data)); |
200 | ASSERT_EQ(data.Pop<uint64_t>(), 0xffffffffffffffff); |
201 | } |
202 | { |
203 | DataStack data; |
204 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_eq}, data)); |
205 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
206 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_eq}, data)); |
207 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
208 | } |
209 | { |
210 | DataStack data; |
211 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_neq}, data)); |
212 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
213 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 0, op_neq}, data)); |
214 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
215 | } |
216 | { |
217 | DataStack data; |
218 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_lt}, data)); |
219 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
220 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_lt}, data)); |
221 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
222 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_lt}, data)); |
223 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
224 | } |
225 | { |
226 | DataStack data; |
227 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_gt}, data)); |
228 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
229 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_gt}, data)); |
230 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
231 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_gt}, data)); |
232 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
233 | } |
234 | { |
235 | DataStack data; |
236 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_le}, data)); |
237 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
238 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_le}, data)); |
239 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
240 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_le}, data)); |
241 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
242 | } |
243 | { |
244 | DataStack data; |
245 | ASSERT_TRUE(Interpret({op_lit_uint, 0, op_lit_uint, 1, op_ge}, data)); |
246 | ASSERT_EQ(data.Pop<uint64_t>(), 0u); |
247 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 0, op_ge}, data)); |
248 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
249 | ASSERT_TRUE(Interpret({op_lit_uint, 1, op_lit_uint, 1, op_ge}, data)); |
250 | ASSERT_EQ(data.Pop<uint64_t>(), 1u); |
251 | } |
252 | } |
253 | |
254 | TEST_F(FormatterBytecodeTest, CallOps) { |
255 | { |
256 | DataStack data; |
257 | data.Push(el: std::string{"hello" }); |
258 | ASSERT_TRUE(Interpret({op_lit_selector, sel_strlen, op_call}, data)); |
259 | ASSERT_EQ(data.Pop<uint64_t>(), 5u); |
260 | } |
261 | { |
262 | DataStack data; |
263 | data.Push(el: std::string{"A" }); |
264 | data.Push(el: std::string{"B" }); |
265 | data.Push(el: std::string{"{1}{0}" }); |
266 | ASSERT_TRUE(Interpret({op_lit_selector, sel_fmt, op_call}, data)); |
267 | ASSERT_EQ(data.Pop<std::string>(), "BA" ); |
268 | } |
269 | { |
270 | DataStack data; |
271 | data.Push(el: std::string{"{0}" }); |
272 | ASSERT_FALSE(Interpret({op_lit_selector, sel_fmt, op_call}, data)); |
273 | } |
274 | } |
275 | |