[go: nahoru, domu]

blob: 6d9dc02bea9bc87bb7f7e1ea056caed065a46b8d [file] [log] [blame]
Charlie Hud5c14032021-08-26 21:45:591// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/profiler/chrome_unwind_table_android.h"
6
7#include "base/test/gtest_util.h"
8#include "build/build_config.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace base {
12
13TEST(ChromeAndroidUnwindInstructionTest,
14 TestSmallStackPointerIncrementMinValue) {
15 RegisterContext thread_context = {};
16 const uint8_t instruction = 0b00000000;
17 const uint8_t* current_instruction = &instruction;
18 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3619 bool pc_was_updated = false;
20 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
21 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5922 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:3623 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5924 ASSERT_EQ(current_instruction, &instruction + 1);
25 EXPECT_EQ(0x10000004ul, thread_context.arm_sp);
26}
27
28TEST(ChromeAndroidUnwindInstructionTest,
29 TestSmallStackPointerIncrementMidValue) {
30 // xxxxxx = 4; vsp = vsp + (4 << 2) + 4 = vsp + 16 + 4 = vsp + 0x14.
31 RegisterContext thread_context = {};
32 const uint8_t instruction = 0b00000100;
33 const uint8_t* current_instruction = &instruction;
34 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3635 bool pc_was_updated = false;
36 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
37 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5938 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:3639 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5940 ASSERT_EQ(current_instruction, &instruction + 1);
41 EXPECT_EQ(0x10000014ul, thread_context.arm_sp);
42}
43
44TEST(ChromeAndroidUnwindInstructionTest,
45 TestSmallStackPointerIncrementMaxValue) {
46 RegisterContext thread_context = {};
47 const uint8_t instruction = 0b00111111;
48 const uint8_t* current_instruction = &instruction;
49 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3650 bool pc_was_updated = false;
51 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
52 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5953 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:3654 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5955 ASSERT_EQ(current_instruction, &instruction + 1);
56 EXPECT_EQ(0x10000100ul, thread_context.arm_sp);
57}
58
59TEST(ChromeAndroidUnwindInstructionTest,
60 TestSmallStackPointerIncrementOverflow) {
61 RegisterContext thread_context = {};
62 const uint8_t instruction = 0b00111111;
63 const uint8_t* current_instruction = &instruction;
64 thread_context.arm_sp = 0xffffffff;
Charlie Hu01b7e662021-09-13 14:51:3665 bool pc_was_updated = false;
66 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
67 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5968 UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
69 ASSERT_EQ(current_instruction, &instruction + 1);
70 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
71}
72
73TEST(ChromeAndroidUnwindInstructionTest,
74 TestSmallStackPointerDecrementMinValue) {
75 RegisterContext thread_context = {};
76 const uint8_t instruction = 0b01000000;
77 const uint8_t* current_instruction = &instruction;
78 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3679 bool pc_was_updated = false;
80 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
81 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5982 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:3683 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5984 ASSERT_EQ(current_instruction, &instruction + 1);
85 EXPECT_EQ(0x0ffffffcul, thread_context.arm_sp);
86}
87
88TEST(ChromeAndroidUnwindInstructionTest,
89 TestSmallStackPointerDecrementMidValue) {
90 // xxxxxx = 4; vsp = vsp - (4 << 2) - 4 = vsp - 16 - 4 = vsp - 0x14.
91 RegisterContext thread_context = {};
92 const uint8_t instruction = 0b01000100;
93 const uint8_t* current_instruction = &instruction;
94 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3695 bool pc_was_updated = false;
96 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
97 &thread_context),
Charlie Hud5c14032021-08-26 21:45:5998 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:3699 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59100 ASSERT_EQ(current_instruction, &instruction + 1);
101 EXPECT_EQ(0x0fffffecul, thread_context.arm_sp);
102}
103
104TEST(ChromeAndroidUnwindInstructionTest,
105 TestSmallStackPointerDecrementMaxValue) {
106 RegisterContext thread_context = {};
107 const uint8_t instruction = 0b01111111;
108 const uint8_t* current_instruction = &instruction;
109 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:36110 bool pc_was_updated = false;
111 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
112 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59113 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36114 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59115 ASSERT_EQ(current_instruction, &instruction + 1);
116 EXPECT_EQ(0x0fffff00ul, thread_context.arm_sp);
117}
118
119TEST(ChromeAndroidUnwindInstructionTest,
120 TestSmallStackPointerDecrementUnderflow) {
121 RegisterContext thread_context = {};
122 const uint8_t instruction = 0b01111111;
123 const uint8_t* current_instruction = &instruction;
124 thread_context.arm_sp = 0x00000000;
Charlie Hu01b7e662021-09-13 14:51:36125 bool pc_was_updated = false;
126 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
127 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59128 UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
Charlie Hu01b7e662021-09-13 14:51:36129 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59130 ASSERT_EQ(current_instruction, &instruction + 1);
131 EXPECT_EQ(0x0ul, thread_context.arm_sp);
132}
133
134using ChromeAndroidUnwindSetStackPointerFromRegisterValueTest =
135 ::testing::TestWithParam<uint8_t>;
136
137INSTANTIATE_TEST_SUITE_P(
138 All,
139 ChromeAndroidUnwindSetStackPointerFromRegisterValueTest,
140 // The function should set all registers except
141 // - callee saved registers (r0, r1, r2, r3)
142 // - sp (r13)
143 // - pc (r15)
144 ::testing::Values(4, 5, 6, 7, 8, 9, 10, 11, 12, 14));
145
146TEST_P(ChromeAndroidUnwindSetStackPointerFromRegisterValueTest,
147 TestSetStackPointerFromRegisterValue) {
148 const uint8_t register_index = GetParam();
149
150 RegisterContext thread_context = {};
151 thread_context.arm_r0 = 100;
152 thread_context.arm_r1 = 101;
153 thread_context.arm_r2 = 102;
154 thread_context.arm_r3 = 103;
155 thread_context.arm_r4 = 104;
156 thread_context.arm_r5 = 105;
157 thread_context.arm_r6 = 106;
158 thread_context.arm_r7 = 107;
159 thread_context.arm_r8 = 108;
160 thread_context.arm_r9 = 109;
161 thread_context.arm_r10 = 110;
162 thread_context.arm_fp = 111; // r11
163 thread_context.arm_ip = 112; // r12
164 thread_context.arm_lr = 114; // r14
165
166 const uint8_t instruction = 0b10010000 + register_index;
167 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36168 bool pc_was_updated = false;
169 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
170 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59171 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36172 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59173 ASSERT_EQ(current_instruction, &instruction + 1);
174 EXPECT_EQ(100ul + register_index, thread_context.arm_sp);
175}
176
Charlie Hu01b7e662021-09-13 14:51:36177TEST(ChromeAndroidUnwindInstructionTest, TestCompleteWithNoPriorPCUpdate) {
Charlie Hud5c14032021-08-26 21:45:59178 RegisterContext thread_context = {};
179 thread_context.arm_lr = 114; // r14
180 thread_context.arm_pc = 115; // r15
Charlie Hud5c14032021-08-26 21:45:59181 const uint8_t instruction = 0b10110000;
182 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36183 bool pc_was_updated = false;
184 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
185 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59186 UnwindInstructionResult::COMPLETED);
187 ASSERT_EQ(current_instruction, &instruction + 1);
188 EXPECT_EQ(114ul, thread_context.arm_pc);
189}
190
Charlie Hu01b7e662021-09-13 14:51:36191TEST(ChromeAndroidUnwindInstructionTest, TestCompleteWithPriorPCUpdate) {
192 RegisterContext thread_context = {};
193 thread_context.arm_lr = 114; // r14
194 thread_context.arm_pc = 115; // r15
195 const uint8_t instruction = 0b10110000;
196 const uint8_t* current_instruction = &instruction;
197 bool pc_was_updated = true;
198 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
199 &thread_context),
200 UnwindInstructionResult::COMPLETED);
201 ASSERT_EQ(current_instruction, &instruction + 1);
202 EXPECT_EQ(115ul, thread_context.arm_pc);
203}
204
205TEST(ChromeAndroidUnwindInstructionTest,
206 TestPopDiscontinuousRegistersIncludingPC) {
207 RegisterContext thread_context = {};
208
209 thread_context.arm_r0 = 100;
210 thread_context.arm_r1 = 101;
211 thread_context.arm_r2 = 102;
212 thread_context.arm_r3 = 103;
213 thread_context.arm_r4 = 104;
214 thread_context.arm_r5 = 105;
215 thread_context.arm_r6 = 106;
216 thread_context.arm_r7 = 107;
217 thread_context.arm_r8 = 108;
218 thread_context.arm_r9 = 109;
219 thread_context.arm_r10 = 110;
220 thread_context.arm_fp = 111;
221 thread_context.arm_ip = 112;
222 thread_context.arm_lr = 113;
223 thread_context.arm_pc = 114;
224
225 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
226 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
227
228 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
229 // Pop r15, r12, r8, r4.
230 const uint8_t instruction[] = {0b10001001, 0b00010001};
231 const uint8_t* current_instruction = instruction;
232
233 bool pc_was_updated = false;
234 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
235 &thread_context),
236 UnwindInstructionResult::INSTRUCTION_PENDING);
237 EXPECT_TRUE(pc_was_updated);
238 ASSERT_EQ(current_instruction, instruction + 2);
239 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 4), thread_context.arm_sp);
240
241 EXPECT_EQ(100ul, thread_context.arm_r0);
242 EXPECT_EQ(101ul, thread_context.arm_r1);
243 EXPECT_EQ(102ul, thread_context.arm_r2);
244 EXPECT_EQ(103ul, thread_context.arm_r3);
245 EXPECT_EQ(1ul, thread_context.arm_r4);
246 EXPECT_EQ(105ul, thread_context.arm_r5);
247 EXPECT_EQ(106ul, thread_context.arm_r6);
248 EXPECT_EQ(107ul, thread_context.arm_r7);
249 EXPECT_EQ(2ul, thread_context.arm_r8);
250 EXPECT_EQ(109ul, thread_context.arm_r9);
251 EXPECT_EQ(110ul, thread_context.arm_r10);
252 EXPECT_EQ(111ul, thread_context.arm_fp);
253 EXPECT_EQ(3ul, thread_context.arm_ip);
254 EXPECT_EQ(113ul, thread_context.arm_lr);
255 EXPECT_EQ(4ul, thread_context.arm_pc);
256}
257
258TEST(ChromeAndroidUnwindInstructionTest, TestPopDiscontinuousRegisters) {
259 RegisterContext thread_context = {};
260
261 thread_context.arm_r0 = 100;
262 thread_context.arm_r1 = 101;
263 thread_context.arm_r2 = 102;
264 thread_context.arm_r3 = 103;
265 thread_context.arm_r4 = 104;
266 thread_context.arm_r5 = 105;
267 thread_context.arm_r6 = 106;
268 thread_context.arm_r7 = 107;
269 thread_context.arm_r8 = 108;
270 thread_context.arm_r9 = 109;
271 thread_context.arm_r10 = 110;
272 thread_context.arm_fp = 111;
273 thread_context.arm_ip = 112;
274 thread_context.arm_lr = 113;
275 thread_context.arm_pc = 114;
276
277 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
278 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
279
280 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
281 // Pop r12, r8, r4.
282 const uint8_t instruction[] = {0b10000001, 0b00010001};
283 const uint8_t* current_instruction = instruction;
284
285 bool pc_was_updated = false;
286 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
287 &thread_context),
288 UnwindInstructionResult::INSTRUCTION_PENDING);
289 EXPECT_FALSE(pc_was_updated);
290 ASSERT_EQ(current_instruction, instruction + 2);
291 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 3), thread_context.arm_sp);
292
293 EXPECT_EQ(100ul, thread_context.arm_r0);
294 EXPECT_EQ(101ul, thread_context.arm_r1);
295 EXPECT_EQ(102ul, thread_context.arm_r2);
296 EXPECT_EQ(103ul, thread_context.arm_r3);
297 EXPECT_EQ(1ul, thread_context.arm_r4);
298 EXPECT_EQ(105ul, thread_context.arm_r5);
299 EXPECT_EQ(106ul, thread_context.arm_r6);
300 EXPECT_EQ(107ul, thread_context.arm_r7);
301 EXPECT_EQ(2ul, thread_context.arm_r8);
302 EXPECT_EQ(109ul, thread_context.arm_r9);
303 EXPECT_EQ(110ul, thread_context.arm_r10);
304 EXPECT_EQ(111ul, thread_context.arm_fp);
305 EXPECT_EQ(3ul, thread_context.arm_ip);
306 EXPECT_EQ(113ul, thread_context.arm_lr);
307 EXPECT_EQ(114ul, thread_context.arm_pc);
308}
309
310TEST(ChromeAndroidUnwindInstructionTest,
311 TestPopDiscontinuousRegistersOverflow) {
312 RegisterContext thread_context = {};
313
314 thread_context.arm_r0 = 100;
315 thread_context.arm_r1 = 101;
316 thread_context.arm_r2 = 102;
317 thread_context.arm_r3 = 103;
318 thread_context.arm_r4 = 104;
319 thread_context.arm_r5 = 105;
320 thread_context.arm_r6 = 106;
321 thread_context.arm_r7 = 107;
322 thread_context.arm_r8 = 108;
323 thread_context.arm_r9 = 109;
324 thread_context.arm_r10 = 110;
325 thread_context.arm_fp = 111;
326 thread_context.arm_ip = 112;
327 thread_context.arm_lr = 113;
328 thread_context.arm_pc = 114;
329
330 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
331 thread_context.arm_sp = 0xffffffff;
332 // Pop r15, r12, r8, r4.
333 const uint8_t instruction[] = {0b10001001, 0b00010001};
334 const uint8_t* current_instruction = instruction;
335
336 bool pc_was_updated = false;
337 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
338 &thread_context),
339 UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
340 EXPECT_FALSE(pc_was_updated);
341 ASSERT_EQ(current_instruction, instruction + 2);
342 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
343
344 EXPECT_EQ(100ul, thread_context.arm_r0);
345 EXPECT_EQ(101ul, thread_context.arm_r1);
346 EXPECT_EQ(102ul, thread_context.arm_r2);
347 EXPECT_EQ(103ul, thread_context.arm_r3);
348 EXPECT_EQ(104ul, thread_context.arm_r4);
349 EXPECT_EQ(105ul, thread_context.arm_r5);
350 EXPECT_EQ(106ul, thread_context.arm_r6);
351 EXPECT_EQ(107ul, thread_context.arm_r7);
352 EXPECT_EQ(108ul, thread_context.arm_r8);
353 EXPECT_EQ(109ul, thread_context.arm_r9);
354 EXPECT_EQ(110ul, thread_context.arm_r10);
355 EXPECT_EQ(111ul, thread_context.arm_fp);
356 EXPECT_EQ(112ul, thread_context.arm_ip);
357 EXPECT_EQ(113ul, thread_context.arm_lr);
358 EXPECT_EQ(114ul, thread_context.arm_pc);
359}
360
Charlie Hud5c14032021-08-26 21:45:59361TEST(ChromeAndroidUnwindInstructionTest,
362 TestPopRegistersIncludingR14MinRegisters) {
363 RegisterContext thread_context = {};
364
365 thread_context.arm_r0 = 100;
366 thread_context.arm_r1 = 101;
367 thread_context.arm_r2 = 102;
368 thread_context.arm_r3 = 103;
369 thread_context.arm_r4 = 104;
370 thread_context.arm_r5 = 105;
371 thread_context.arm_r6 = 106;
372 thread_context.arm_r7 = 107;
373 thread_context.arm_r8 = 108;
374 thread_context.arm_r9 = 109;
375 thread_context.arm_r10 = 110;
376 thread_context.arm_fp = 111;
377 thread_context.arm_ip = 112;
378 thread_context.arm_lr = 113;
379
380 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
381 // r14 = lr
382 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
383
384 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
385 const uint8_t instruction = 0b10101000;
386 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36387 bool pc_was_updated = false;
388 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
389 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59390 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36391 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59392 ASSERT_EQ(current_instruction, &instruction + 1);
393 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 2), thread_context.arm_sp);
394
395 EXPECT_EQ(100ul, thread_context.arm_r0);
396 EXPECT_EQ(101ul, thread_context.arm_r1);
397 EXPECT_EQ(102ul, thread_context.arm_r2);
398 EXPECT_EQ(103ul, thread_context.arm_r3);
399 EXPECT_EQ(1ul, thread_context.arm_r4);
400 EXPECT_EQ(105ul, thread_context.arm_r5);
401 EXPECT_EQ(106ul, thread_context.arm_r6);
402 EXPECT_EQ(107ul, thread_context.arm_r7);
403 EXPECT_EQ(108ul, thread_context.arm_r8);
404 EXPECT_EQ(109ul, thread_context.arm_r9);
405 EXPECT_EQ(110ul, thread_context.arm_r10);
406 EXPECT_EQ(111ul, thread_context.arm_fp);
407 EXPECT_EQ(112ul, thread_context.arm_ip);
408 EXPECT_EQ(2ul, thread_context.arm_lr);
409}
410
411TEST(ChromeAndroidUnwindInstructionTest,
412 TestPopRegistersIncludingR14MidRegisters) {
413 RegisterContext thread_context = {};
414
415 thread_context.arm_r0 = 100;
416 thread_context.arm_r1 = 101;
417 thread_context.arm_r2 = 102;
418 thread_context.arm_r3 = 103;
419 thread_context.arm_r4 = 104;
420 thread_context.arm_r5 = 105;
421 thread_context.arm_r6 = 106;
422 thread_context.arm_r7 = 107;
423 thread_context.arm_r8 = 108;
424 thread_context.arm_r9 = 109;
425 thread_context.arm_r10 = 110;
426 thread_context.arm_fp = 111;
427 thread_context.arm_ip = 112;
428 thread_context.arm_lr = 113;
429
430 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
431 // r14 = lr
432 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
433
434 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
435 const uint8_t instruction = 0b10101100; // Pop r4-r8, r14.
436 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36437 bool pc_was_updated = false;
438 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
439 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59440 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36441 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59442 ASSERT_EQ(current_instruction, &instruction + 1);
443 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 6), thread_context.arm_sp);
444
445 EXPECT_EQ(100ul, thread_context.arm_r0);
446 EXPECT_EQ(101ul, thread_context.arm_r1);
447 EXPECT_EQ(102ul, thread_context.arm_r2);
448 EXPECT_EQ(103ul, thread_context.arm_r3);
449 EXPECT_EQ(1ul, thread_context.arm_r4);
450 EXPECT_EQ(2ul, thread_context.arm_r5);
451 EXPECT_EQ(3ul, thread_context.arm_r6);
452 EXPECT_EQ(4ul, thread_context.arm_r7);
453 EXPECT_EQ(5ul, thread_context.arm_r8);
454 EXPECT_EQ(109ul, thread_context.arm_r9);
455 EXPECT_EQ(110ul, thread_context.arm_r10);
456 EXPECT_EQ(111ul, thread_context.arm_fp);
457 EXPECT_EQ(112ul, thread_context.arm_ip);
458 EXPECT_EQ(6ul, thread_context.arm_lr);
459}
460
461TEST(ChromeAndroidUnwindInstructionTest,
462 TestPopRegistersIncludingR14MaxRegisters) {
463 RegisterContext thread_context = {};
464
465 thread_context.arm_r0 = 100;
466 thread_context.arm_r1 = 101;
467 thread_context.arm_r2 = 102;
468 thread_context.arm_r3 = 103;
469 thread_context.arm_r4 = 104;
470 thread_context.arm_r5 = 105;
471 thread_context.arm_r6 = 106;
472 thread_context.arm_r7 = 107;
473 thread_context.arm_r8 = 108;
474 thread_context.arm_r9 = 109;
475 thread_context.arm_r10 = 110;
476 thread_context.arm_fp = 111;
477 thread_context.arm_ip = 112;
478 thread_context.arm_lr = 113;
479
480 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
481 // r14 = lr
482 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
483
484 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
485 const uint8_t instruction = 0b10101111; // Pop r4 - r11, r14.
486 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36487 bool pc_was_updated = false;
488 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
489 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59490 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36491 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59492 ASSERT_EQ(current_instruction, &instruction + 1);
493 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 9), thread_context.arm_sp);
494
495 EXPECT_EQ(100ul, thread_context.arm_r0);
496 EXPECT_EQ(101ul, thread_context.arm_r1);
497 EXPECT_EQ(102ul, thread_context.arm_r2);
498 EXPECT_EQ(103ul, thread_context.arm_r3);
499 EXPECT_EQ(1ul, thread_context.arm_r4);
500 EXPECT_EQ(2ul, thread_context.arm_r5);
501 EXPECT_EQ(3ul, thread_context.arm_r6);
502 EXPECT_EQ(4ul, thread_context.arm_r7);
503 EXPECT_EQ(5ul, thread_context.arm_r8);
504 EXPECT_EQ(6ul, thread_context.arm_r9);
505 EXPECT_EQ(7ul, thread_context.arm_r10);
506 EXPECT_EQ(8ul, thread_context.arm_fp);
507 EXPECT_EQ(112ul, thread_context.arm_ip);
508 EXPECT_EQ(9ul, thread_context.arm_lr);
509}
510
511TEST(ChromeAndroidUnwindInstructionTest, TestPopRegistersIncludingR14Overflow) {
512 RegisterContext thread_context = {};
513
514 thread_context.arm_r0 = 100;
515 thread_context.arm_r1 = 101;
516 thread_context.arm_r2 = 102;
517 thread_context.arm_r3 = 103;
518 thread_context.arm_r4 = 104;
519 thread_context.arm_r5 = 105;
520 thread_context.arm_r6 = 106;
521 thread_context.arm_r7 = 107;
522 thread_context.arm_r8 = 108;
523 thread_context.arm_r9 = 109;
524 thread_context.arm_r10 = 110;
525 thread_context.arm_fp = 111;
526 thread_context.arm_ip = 112;
527 thread_context.arm_lr = 113;
528
529 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
530 // r14 = lr
531 thread_context.arm_sp = 0xffffffff;
532 const uint8_t instruction = 0b10101111; // Pop r4 - r11, r14.
533 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36534 bool pc_was_updated = false;
535 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
536 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59537 UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
Charlie Hu01b7e662021-09-13 14:51:36538 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59539 ASSERT_EQ(current_instruction, &instruction + 1);
540 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
541
542 EXPECT_EQ(100ul, thread_context.arm_r0);
543 EXPECT_EQ(101ul, thread_context.arm_r1);
544 EXPECT_EQ(102ul, thread_context.arm_r2);
545 EXPECT_EQ(103ul, thread_context.arm_r3);
546 EXPECT_EQ(104ul, thread_context.arm_r4);
547 EXPECT_EQ(105ul, thread_context.arm_r5);
548 EXPECT_EQ(106ul, thread_context.arm_r6);
549 EXPECT_EQ(107ul, thread_context.arm_r7);
550 EXPECT_EQ(108ul, thread_context.arm_r8);
551 EXPECT_EQ(109ul, thread_context.arm_r9);
552 EXPECT_EQ(110ul, thread_context.arm_r10);
553 EXPECT_EQ(111ul, thread_context.arm_fp);
554 EXPECT_EQ(112ul, thread_context.arm_ip);
555 EXPECT_EQ(113ul, thread_context.arm_lr);
556}
557
558TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementMinValue) {
559 RegisterContext thread_context = {};
560 thread_context.arm_sp = 0x10000000;
561
562 const uint8_t increment_0[] = {
563 0b10110010,
564 0b00000000,
565 };
566 const uint8_t* current_instruction = &increment_0[0];
Charlie Hu01b7e662021-09-13 14:51:36567 bool pc_was_updated = false;
568 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
569 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59570 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36571 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59572 ASSERT_EQ(current_instruction, increment_0 + sizeof(increment_0));
573 // vsp + 0x204 + (0 << 2)
574 // = vsp + 0x204
575 EXPECT_EQ(0x10000204ul, thread_context.arm_sp);
576}
577
578TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementMidValue) {
579 RegisterContext thread_context = {};
580 thread_context.arm_sp = 0x10000000;
581
582 const uint8_t increment_4[] = {
583 0b10110010,
584 0b00000100,
585 };
586 const uint8_t* current_instruction = &increment_4[0];
587
588 // vsp + 0x204 + (4 << 2)
589 // = vsp + 0x204 + 0x10
590 // = vsp + 0x214
Charlie Hu01b7e662021-09-13 14:51:36591 bool pc_was_updated = false;
592 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
593 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59594 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36595 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59596 ASSERT_EQ(current_instruction, increment_4 + sizeof(increment_4));
597 EXPECT_EQ(0x10000214ul, thread_context.arm_sp);
598}
599
600TEST(ChromeAndroidUnwindInstructionTest,
601 TestBigStackPointerIncrementLargeValue) {
602 RegisterContext thread_context = {};
603 thread_context.arm_sp = 0x10000000;
604
605 const uint8_t increment_128[] = {
606 0b10110010,
607 0b10000000,
608 0b00000001,
609 };
610 const uint8_t* current_instruction = &increment_128[0];
611 // vsp + 0x204 + (128 << 2)
612 // = vsp + 0x204 + 512
613 // = vsp + 0x204 + 0x200
614 // = vsp + 0x404
Charlie Hu01b7e662021-09-13 14:51:36615 bool pc_was_updated = false;
616 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
617 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59618 UnwindInstructionResult::INSTRUCTION_PENDING);
Charlie Hu01b7e662021-09-13 14:51:36619 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59620 ASSERT_EQ(current_instruction, increment_128 + sizeof(increment_128));
621 EXPECT_EQ(0x10000404ul, thread_context.arm_sp);
622}
623
624TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementOverflow) {
625 RegisterContext thread_context = {};
626 thread_context.arm_sp = 0xffffffff;
627
628 const uint8_t increment_overflow[] = {
629 0b10110010,
630 0b10000000,
631 0b00000001,
632 }; // ULEB128 = 128
633 const uint8_t* current_instruction = &increment_overflow[0];
Charlie Hu01b7e662021-09-13 14:51:36634 bool pc_was_updated = false;
635 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
636 &thread_context),
Charlie Hud5c14032021-08-26 21:45:59637 UnwindInstructionResult::STACK_POINTER_OUT_OF_BOUNDS);
Charlie Hu01b7e662021-09-13 14:51:36638 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59639 ASSERT_EQ(current_instruction,
640 increment_overflow + sizeof(increment_overflow));
641 EXPECT_EQ(0xfffffffful, thread_context.arm_sp);
642}
643
Charlie Huf36b2f62021-09-01 22:31:20644TEST(ChromeUnwindTableAndroidTest,
645 TestFunctionOffsetTableLookupExactMatchingOffset) {
646 const uint8_t unwind_instruction_table[] = {0, 1, 2, 3, 4, 5, 6};
647 const uint8_t function_offset_table[] = {
648 // Function 1: [(130, 2), (128, 3), (0, 4)]
649 // offset = 130
650 0b10000010,
651 0b00000001,
652 // unwind index = 2
653 0b00000010,
654 // offset = 128
655 0b10000000,
656 0b00000001,
657 // unwind index = 3
658 0b00000011,
659 // offset = 0
660 0b00000000,
661 // unwind index = 4
662 0b00000100,
663 };
664
665 EXPECT_EQ(unwind_instruction_table + 3,
Charlie Hu235c6b72021-09-13 20:50:01666 GetFirstUnwindInstructionFromFunctionOffsetTableIndex(
Charlie Huf36b2f62021-09-01 22:31:20667 unwind_instruction_table, function_offset_table,
Charlie Hu235c6b72021-09-13 20:50:01668 {/* instruction_offset_from_function_start */ 128,
669 /* function_offset_table_byte_index */ 0x0}));
Charlie Huf36b2f62021-09-01 22:31:20670}
671
672TEST(ChromeUnwindTableAndroidTest,
673 TestFunctionOffsetTableLookupNonExactMatchingOffset) {
674 const uint8_t unwind_instruction_table[] = {0, 1, 2, 3, 4, 5, 6};
675 const uint8_t function_offset_table[] = {
676 // Function 1: [(130, 2), (128, 3), (0, 4)]
677 // offset = 130
678 0b10000010,
679 0b00000001,
680 // unwind index = 2
681 0b00000010,
682 // offset = 128
683 0b10000000,
684 0b00000001,
685 // unwind index = 3
686 0b00000011,
687 // offset = 0
688 0b00000000,
689 // unwind index = 4
690 0b00000100,
691 };
692
693 EXPECT_EQ(unwind_instruction_table + 3,
Charlie Hu235c6b72021-09-13 20:50:01694 GetFirstUnwindInstructionFromFunctionOffsetTableIndex(
Charlie Huf36b2f62021-09-01 22:31:20695 unwind_instruction_table, function_offset_table,
Charlie Hu235c6b72021-09-13 20:50:01696 {/* instruction_offset_from_function_start */ 129,
697 /* function_offset_table_byte_index */ 0x0}));
Charlie Huf36b2f62021-09-01 22:31:20698}
699
700TEST(ChromeUnwindTableAndroidTest, TestFunctionOffsetTableLookupZeroOffset) {
701 const uint8_t unwind_instruction_table[] = {0, 1, 2, 3, 4, 5, 6};
702 const uint8_t function_offset_table[] = {
703 // Function 1: [(130, 2), (128, 3), (0, 4)]
704 // offset = 130
705 0b10000010,
706 0b00000001,
707 // unwind index = 2
708 0b00000010,
709 // offset = 128
710 0b10000000,
711 0b00000001,
712 // unwind index = 3
713 0b00000011,
714 // offset = 0
715 0b00000000,
716 // unwind index = 4
717 0b00000100,
718 };
719
720 EXPECT_EQ(unwind_instruction_table + 4,
Charlie Hu235c6b72021-09-13 20:50:01721 GetFirstUnwindInstructionFromFunctionOffsetTableIndex(
Charlie Huf36b2f62021-09-01 22:31:20722 unwind_instruction_table, function_offset_table,
Charlie Hu235c6b72021-09-13 20:50:01723 {/* instruction_offset_from_function_start */ 0,
724 /* function_offset_table_byte_index */ 0x0}));
Charlie Huf36b2f62021-09-01 22:31:20725}
726
Charlie Hu235c6b72021-09-13 20:50:01727TEST(ChromeUnwindTableAndroidTest, TestAddressTableLookupEntryInPage) {
728 const uint32_t page_start_instructions[] = {0, 2};
729 const FunctionTableEntry function_offset_table_indices[] = {
730 // Page 0
731 {
732 /* function_start_address_page_instruction_offset */ 0,
733 /* function_offset_table_byte_index */ 20,
734 },
735 {
736 /* function_start_address_page_instruction_offset */ 4,
737 /* function_offset_table_byte_index */ 40,
738 },
739 // Page 1
740 {
741 /* function_start_address_page_instruction_offset */ 6,
742 /* function_offset_table_byte_index */ 70,
743 },
744 };
745
746 {
747 const uint32_t page_number = 0;
748 const uint32_t page_instruction_offset = 4;
749 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
750 page_start_instructions, function_offset_table_indices,
751 /* instruction_offset */ (page_instruction_offset << 1) +
752 (page_number << 17));
753 ASSERT_NE(absl::nullopt, entry_found);
754 EXPECT_EQ(0, entry_found->instruction_offset_from_function_start);
755 EXPECT_EQ(40ul, entry_found->function_offset_table_byte_index);
756 }
757
758 {
759 const uint32_t page_number = 0;
760 const uint32_t page_instruction_offset = 50;
761 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
762 page_start_instructions, function_offset_table_indices,
763 /* instruction_offset */ (page_instruction_offset << 1) +
764 (page_number << 17));
765 ASSERT_NE(absl::nullopt, entry_found);
766 EXPECT_EQ(46, entry_found->instruction_offset_from_function_start);
767 EXPECT_EQ(40ul, entry_found->function_offset_table_byte_index);
768 }
769
770 // Lookup last instruction in last function.
771 {
772 const uint32_t page_number = 1;
773 const uint32_t page_instruction_offset = 0xffff;
774 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
775 page_start_instructions, function_offset_table_indices,
776 /* instruction_offset */ (page_instruction_offset << 1) +
777 (page_number << 17));
778 ASSERT_NE(absl::nullopt, entry_found);
779 // 0xffff - 6 = 0xfff9.
780 EXPECT_EQ(0xfff9, entry_found->instruction_offset_from_function_start);
781 EXPECT_EQ(70ul, entry_found->function_offset_table_byte_index);
782 }
783}
784
785TEST(ChromeUnwindTableAndroidTest, TestAddressTableLookupEmptyPage) {
786 const uint32_t page_start_instructions[] = {0, 1, 1};
787 const FunctionTableEntry function_offset_table_indices[] = {
788 // Page 0
789 {
790 /* function_start_address_page_instruction_offset */ 0,
791 /* function_offset_table_byte_index */ 20,
792 },
793 // Page 1 is empty
794 // Page 2
795 {
796 /* function_start_address_page_instruction_offset */ 6,
797 /* function_offset_table_byte_index */ 70,
798 },
799 };
800
801 const uint32_t page_number = 1;
802 const uint32_t page_instruction_offset = 4;
803 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
804 page_start_instructions, function_offset_table_indices,
805 /* instruction_offset */ (page_instruction_offset << 1) +
806 (page_number << 17));
807 ASSERT_NE(absl::nullopt, entry_found);
808 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
809 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
810}
811
812TEST(ChromeUnwindTableAndroidTest,
813 TestAddressTableLookupInvalidIntructionOffset) {
814 const uint32_t page_start_instructions[] = {0, 1};
815 const FunctionTableEntry function_offset_table_indices[] = {
816 // Page 0
817 // This function spans from page 0 offset 0 to page 1 offset 5.
818 {
819 /* function_start_address_page_instruction_offset */ 0,
820 /* function_offset_table_byte_index */ 20,
821 },
822 // Page 1
823 {
824 /* function_start_address_page_instruction_offset */ 6,
825 /* function_offset_table_byte_index */ 70,
826 },
827 };
828
829 // Instruction offset lies after last page on page table.
830 {
831 const uint32_t page_number = 50;
832 const uint32_t page_instruction_offset = 6;
833 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
834 page_start_instructions, function_offset_table_indices,
835 /* instruction_offset */ (page_instruction_offset << 1) +
836 (page_number << 17));
837 ASSERT_EQ(absl::nullopt, entry_found);
838 }
839 {
840 const uint32_t page_number = 2;
841 const uint32_t page_instruction_offset = 0;
842 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
843 page_start_instructions, function_offset_table_indices,
844 /* instruction_offset */ (page_instruction_offset << 1) +
845 (page_number << 17));
846 ASSERT_EQ(absl::nullopt, entry_found);
847 }
848}
849
850TEST(ChromeUnwindTableAndroidTest,
851 TestAddressTableLookupOnSecondPageOfFunctionSpanningPageBoundary) {
852 const uint32_t page_start_instructions[] = {0, 1, 2};
853 const FunctionTableEntry function_offset_table_indices[] = {
854 // Page 0
855 {
856 /* function_start_address_page_instruction_offset */ 0,
857 /* function_offset_table_byte_index */ 20,
858 },
859 // Page 1
860 {
861 /* function_start_address_page_instruction_offset */ 6,
862 /* function_offset_table_byte_index */ 70,
863 },
864 // Page 2
865 {
866 /* function_start_address_page_instruction_offset */ 10,
867 /* function_offset_table_byte_index */ 80,
868 }};
869
870 const uint32_t page_number = 1;
871 const uint32_t page_instruction_offset = 4;
872 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
873 page_start_instructions, function_offset_table_indices,
874 /* instruction_offset */ (page_instruction_offset << 1) +
875 (page_number << 17));
876 ASSERT_NE(absl::nullopt, entry_found);
877 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
878 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
879}
880
881TEST(ChromeUnwindTableAndroidTest,
882 TestAddressTableLookupWithinFunctionSpanningMultiplePages) {
883 const uint32_t page_start_instructions[] = {0, 1, 1, 1};
884 const FunctionTableEntry function_offset_table_indices[] = {
885 // Page 0
886 // This function spans from page 0 offset 0 to page 3 offset 5.
887 {
888 /* function_start_address_page_instruction_offset */ 0,
889 /* function_offset_table_byte_index */ 20,
890 },
891 // Page 1 is empty
892 // Page 2 is empty
893 // Page 3
894 {
895 /* function_start_address_page_instruction_offset */ 6,
896 /* function_offset_table_byte_index */ 70,
897 },
898 };
899
900 {
901 const uint32_t page_number = 0;
902 const uint32_t page_instruction_offset = 4;
903 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
904 page_start_instructions, function_offset_table_indices,
905 /* instruction_offset */ (page_instruction_offset << 1) +
906 (page_number << 17));
907 ASSERT_NE(absl::nullopt, entry_found);
908 EXPECT_EQ(0x4, entry_found->instruction_offset_from_function_start);
909 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
910 }
911 {
912 const uint32_t page_number = 1;
913 const uint32_t page_instruction_offset = 4;
914 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
915 page_start_instructions, function_offset_table_indices,
916 /* instruction_offset */ (page_instruction_offset << 1) +
917 (page_number << 17));
918 ASSERT_NE(absl::nullopt, entry_found);
919 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
920 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
921 }
922 {
923 const uint32_t page_number = 2;
924 const uint32_t page_instruction_offset = 4;
925 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
926 page_start_instructions, function_offset_table_indices,
927 /* instruction_offset */ (page_instruction_offset << 1) +
928 (page_number << 17));
929 ASSERT_NE(absl::nullopt, entry_found);
930 EXPECT_EQ(0x20004, entry_found->instruction_offset_from_function_start);
931 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
932 }
933 {
934 const uint32_t page_number = 3;
935 const uint32_t page_instruction_offset = 4;
936 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
937 page_start_instructions, function_offset_table_indices,
938 /* instruction_offset */ (page_instruction_offset << 1) +
939 (page_number << 17));
940 ASSERT_NE(absl::nullopt, entry_found);
941 EXPECT_EQ(0x30004, entry_found->instruction_offset_from_function_start);
942 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
943 }
944}
Charlie Hud5c14032021-08-26 21:45:59945} // namespace base