[go: nahoru, domu]

blob: 8f14225db27811b6115b67624c96e2f061625d37 [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
Charlie Hue0a13a72021-09-24 21:57:395#include "base/profiler/chrome_unwinder_android_v2.h"
Charlie Hud5c14032021-08-26 21:45:596
Charlie Hu027f8a12021-09-23 23:25:197#include "base/profiler/chrome_unwind_info_android.h"
Charlie Hud5c14032021-08-26 21:45:598#include "base/test/gtest_util.h"
9#include "build/build_config.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace base {
13
14TEST(ChromeAndroidUnwindInstructionTest,
15 TestSmallStackPointerIncrementMinValue) {
16 RegisterContext thread_context = {};
17 const uint8_t instruction = 0b00000000;
18 const uint8_t* current_instruction = &instruction;
19 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3620 bool pc_was_updated = false;
21 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
22 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5523 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:3624 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5925 ASSERT_EQ(current_instruction, &instruction + 1);
26 EXPECT_EQ(0x10000004ul, thread_context.arm_sp);
27}
28
29TEST(ChromeAndroidUnwindInstructionTest,
30 TestSmallStackPointerIncrementMidValue) {
31 // xxxxxx = 4; vsp = vsp + (4 << 2) + 4 = vsp + 16 + 4 = vsp + 0x14.
32 RegisterContext thread_context = {};
33 const uint8_t instruction = 0b00000100;
34 const uint8_t* current_instruction = &instruction;
35 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3636 bool pc_was_updated = false;
37 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
38 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5539 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:3640 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5941 ASSERT_EQ(current_instruction, &instruction + 1);
42 EXPECT_EQ(0x10000014ul, thread_context.arm_sp);
43}
44
45TEST(ChromeAndroidUnwindInstructionTest,
46 TestSmallStackPointerIncrementMaxValue) {
47 RegisterContext thread_context = {};
48 const uint8_t instruction = 0b00111111;
49 const uint8_t* current_instruction = &instruction;
50 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3651 bool pc_was_updated = false;
52 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
53 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5554 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:3655 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5956 ASSERT_EQ(current_instruction, &instruction + 1);
57 EXPECT_EQ(0x10000100ul, thread_context.arm_sp);
58}
59
60TEST(ChromeAndroidUnwindInstructionTest,
61 TestSmallStackPointerIncrementOverflow) {
62 RegisterContext thread_context = {};
63 const uint8_t instruction = 0b00111111;
64 const uint8_t* current_instruction = &instruction;
65 thread_context.arm_sp = 0xffffffff;
Charlie Hu01b7e662021-09-13 14:51:3666 bool pc_was_updated = false;
67 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
68 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5569 UnwindInstructionResult::kAborted);
Charlie Hud5c14032021-08-26 21:45:5970 ASSERT_EQ(current_instruction, &instruction + 1);
71 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
72}
73
74TEST(ChromeAndroidUnwindInstructionTest,
75 TestSmallStackPointerDecrementMinValue) {
76 RegisterContext thread_context = {};
77 const uint8_t instruction = 0b01000000;
78 const uint8_t* current_instruction = &instruction;
79 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3680 bool pc_was_updated = false;
81 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
82 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5583 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:3684 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:5985 ASSERT_EQ(current_instruction, &instruction + 1);
86 EXPECT_EQ(0x0ffffffcul, thread_context.arm_sp);
87}
88
89TEST(ChromeAndroidUnwindInstructionTest,
90 TestSmallStackPointerDecrementMidValue) {
91 // xxxxxx = 4; vsp = vsp - (4 << 2) - 4 = vsp - 16 - 4 = vsp - 0x14.
92 RegisterContext thread_context = {};
93 const uint8_t instruction = 0b01000100;
94 const uint8_t* current_instruction = &instruction;
95 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:3696 bool pc_was_updated = false;
97 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
98 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:5599 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36100 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59101 ASSERT_EQ(current_instruction, &instruction + 1);
102 EXPECT_EQ(0x0fffffecul, thread_context.arm_sp);
103}
104
105TEST(ChromeAndroidUnwindInstructionTest,
106 TestSmallStackPointerDecrementMaxValue) {
107 RegisterContext thread_context = {};
108 const uint8_t instruction = 0b01111111;
109 const uint8_t* current_instruction = &instruction;
110 thread_context.arm_sp = 0x10000000;
Charlie Hu01b7e662021-09-13 14:51:36111 bool pc_was_updated = false;
112 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
113 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55114 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36115 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59116 ASSERT_EQ(current_instruction, &instruction + 1);
117 EXPECT_EQ(0x0fffff00ul, thread_context.arm_sp);
118}
119
120TEST(ChromeAndroidUnwindInstructionTest,
121 TestSmallStackPointerDecrementUnderflow) {
122 RegisterContext thread_context = {};
123 const uint8_t instruction = 0b01111111;
124 const uint8_t* current_instruction = &instruction;
125 thread_context.arm_sp = 0x00000000;
Charlie Hu01b7e662021-09-13 14:51:36126 bool pc_was_updated = false;
127 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
128 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55129 UnwindInstructionResult::kAborted);
Charlie Hu01b7e662021-09-13 14:51:36130 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59131 ASSERT_EQ(current_instruction, &instruction + 1);
132 EXPECT_EQ(0x0ul, thread_context.arm_sp);
133}
134
135using ChromeAndroidUnwindSetStackPointerFromRegisterValueTest =
136 ::testing::TestWithParam<uint8_t>;
137
138INSTANTIATE_TEST_SUITE_P(
139 All,
140 ChromeAndroidUnwindSetStackPointerFromRegisterValueTest,
141 // The function should set all registers except
142 // - callee saved registers (r0, r1, r2, r3)
143 // - sp (r13)
144 // - pc (r15)
145 ::testing::Values(4, 5, 6, 7, 8, 9, 10, 11, 12, 14));
146
147TEST_P(ChromeAndroidUnwindSetStackPointerFromRegisterValueTest,
148 TestSetStackPointerFromRegisterValue) {
149 const uint8_t register_index = GetParam();
150
151 RegisterContext thread_context = {};
152 thread_context.arm_r0 = 100;
153 thread_context.arm_r1 = 101;
154 thread_context.arm_r2 = 102;
155 thread_context.arm_r3 = 103;
156 thread_context.arm_r4 = 104;
157 thread_context.arm_r5 = 105;
158 thread_context.arm_r6 = 106;
159 thread_context.arm_r7 = 107;
160 thread_context.arm_r8 = 108;
161 thread_context.arm_r9 = 109;
162 thread_context.arm_r10 = 110;
163 thread_context.arm_fp = 111; // r11
164 thread_context.arm_ip = 112; // r12
165 thread_context.arm_lr = 114; // r14
166
167 const uint8_t instruction = 0b10010000 + register_index;
168 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36169 bool pc_was_updated = false;
170 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
171 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55172 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36173 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59174 ASSERT_EQ(current_instruction, &instruction + 1);
175 EXPECT_EQ(100ul + register_index, thread_context.arm_sp);
176}
177
Charlie Hu01b7e662021-09-13 14:51:36178TEST(ChromeAndroidUnwindInstructionTest, TestCompleteWithNoPriorPCUpdate) {
Charlie Hud5c14032021-08-26 21:45:59179 RegisterContext thread_context = {};
180 thread_context.arm_lr = 114; // r14
181 thread_context.arm_pc = 115; // r15
Charlie Hud5c14032021-08-26 21:45:59182 const uint8_t instruction = 0b10110000;
183 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36184 bool pc_was_updated = false;
185 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
186 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55187 UnwindInstructionResult::kCompleted);
Charlie Hud5c14032021-08-26 21:45:59188 ASSERT_EQ(current_instruction, &instruction + 1);
189 EXPECT_EQ(114ul, thread_context.arm_pc);
190}
191
Charlie Hu01b7e662021-09-13 14:51:36192TEST(ChromeAndroidUnwindInstructionTest, TestCompleteWithPriorPCUpdate) {
193 RegisterContext thread_context = {};
194 thread_context.arm_lr = 114; // r14
195 thread_context.arm_pc = 115; // r15
196 const uint8_t instruction = 0b10110000;
197 const uint8_t* current_instruction = &instruction;
198 bool pc_was_updated = true;
199 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
200 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55201 UnwindInstructionResult::kCompleted);
Charlie Hu01b7e662021-09-13 14:51:36202 ASSERT_EQ(current_instruction, &instruction + 1);
203 EXPECT_EQ(115ul, thread_context.arm_pc);
204}
205
206TEST(ChromeAndroidUnwindInstructionTest,
207 TestPopDiscontinuousRegistersIncludingPC) {
208 RegisterContext thread_context = {};
209
210 thread_context.arm_r0 = 100;
211 thread_context.arm_r1 = 101;
212 thread_context.arm_r2 = 102;
213 thread_context.arm_r3 = 103;
214 thread_context.arm_r4 = 104;
215 thread_context.arm_r5 = 105;
216 thread_context.arm_r6 = 106;
217 thread_context.arm_r7 = 107;
218 thread_context.arm_r8 = 108;
219 thread_context.arm_r9 = 109;
220 thread_context.arm_r10 = 110;
221 thread_context.arm_fp = 111;
222 thread_context.arm_ip = 112;
223 thread_context.arm_lr = 113;
224 thread_context.arm_pc = 114;
225
226 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
227 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
228
229 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
230 // Pop r15, r12, r8, r4.
231 const uint8_t instruction[] = {0b10001001, 0b00010001};
232 const uint8_t* current_instruction = instruction;
233
234 bool pc_was_updated = false;
235 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
236 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55237 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36238 EXPECT_TRUE(pc_was_updated);
239 ASSERT_EQ(current_instruction, instruction + 2);
240 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 4), thread_context.arm_sp);
241
242 EXPECT_EQ(100ul, thread_context.arm_r0);
243 EXPECT_EQ(101ul, thread_context.arm_r1);
244 EXPECT_EQ(102ul, thread_context.arm_r2);
245 EXPECT_EQ(103ul, thread_context.arm_r3);
246 EXPECT_EQ(1ul, thread_context.arm_r4);
247 EXPECT_EQ(105ul, thread_context.arm_r5);
248 EXPECT_EQ(106ul, thread_context.arm_r6);
249 EXPECT_EQ(107ul, thread_context.arm_r7);
250 EXPECT_EQ(2ul, thread_context.arm_r8);
251 EXPECT_EQ(109ul, thread_context.arm_r9);
252 EXPECT_EQ(110ul, thread_context.arm_r10);
253 EXPECT_EQ(111ul, thread_context.arm_fp);
254 EXPECT_EQ(3ul, thread_context.arm_ip);
255 EXPECT_EQ(113ul, thread_context.arm_lr);
256 EXPECT_EQ(4ul, thread_context.arm_pc);
257}
258
259TEST(ChromeAndroidUnwindInstructionTest, TestPopDiscontinuousRegisters) {
260 RegisterContext thread_context = {};
261
262 thread_context.arm_r0 = 100;
263 thread_context.arm_r1 = 101;
264 thread_context.arm_r2 = 102;
265 thread_context.arm_r3 = 103;
266 thread_context.arm_r4 = 104;
267 thread_context.arm_r5 = 105;
268 thread_context.arm_r6 = 106;
269 thread_context.arm_r7 = 107;
270 thread_context.arm_r8 = 108;
271 thread_context.arm_r9 = 109;
272 thread_context.arm_r10 = 110;
273 thread_context.arm_fp = 111;
274 thread_context.arm_ip = 112;
275 thread_context.arm_lr = 113;
276 thread_context.arm_pc = 114;
277
278 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
279 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
280
281 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
282 // Pop r12, r8, r4.
283 const uint8_t instruction[] = {0b10000001, 0b00010001};
284 const uint8_t* current_instruction = instruction;
285
286 bool pc_was_updated = false;
287 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
288 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55289 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36290 EXPECT_FALSE(pc_was_updated);
291 ASSERT_EQ(current_instruction, instruction + 2);
292 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 3), thread_context.arm_sp);
293
294 EXPECT_EQ(100ul, thread_context.arm_r0);
295 EXPECT_EQ(101ul, thread_context.arm_r1);
296 EXPECT_EQ(102ul, thread_context.arm_r2);
297 EXPECT_EQ(103ul, thread_context.arm_r3);
298 EXPECT_EQ(1ul, thread_context.arm_r4);
299 EXPECT_EQ(105ul, thread_context.arm_r5);
300 EXPECT_EQ(106ul, thread_context.arm_r6);
301 EXPECT_EQ(107ul, thread_context.arm_r7);
302 EXPECT_EQ(2ul, thread_context.arm_r8);
303 EXPECT_EQ(109ul, thread_context.arm_r9);
304 EXPECT_EQ(110ul, thread_context.arm_r10);
305 EXPECT_EQ(111ul, thread_context.arm_fp);
306 EXPECT_EQ(3ul, thread_context.arm_ip);
307 EXPECT_EQ(113ul, thread_context.arm_lr);
308 EXPECT_EQ(114ul, thread_context.arm_pc);
309}
310
311TEST(ChromeAndroidUnwindInstructionTest,
312 TestPopDiscontinuousRegistersOverflow) {
313 RegisterContext thread_context = {};
314
315 thread_context.arm_r0 = 100;
316 thread_context.arm_r1 = 101;
317 thread_context.arm_r2 = 102;
318 thread_context.arm_r3 = 103;
319 thread_context.arm_r4 = 104;
320 thread_context.arm_r5 = 105;
321 thread_context.arm_r6 = 106;
322 thread_context.arm_r7 = 107;
323 thread_context.arm_r8 = 108;
324 thread_context.arm_r9 = 109;
325 thread_context.arm_r10 = 110;
326 thread_context.arm_fp = 111;
327 thread_context.arm_ip = 112;
328 thread_context.arm_lr = 113;
329 thread_context.arm_pc = 114;
330
331 // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}.
332 thread_context.arm_sp = 0xffffffff;
333 // Pop r15, r12, r8, r4.
334 const uint8_t instruction[] = {0b10001001, 0b00010001};
335 const uint8_t* current_instruction = instruction;
336
337 bool pc_was_updated = false;
338 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
339 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55340 UnwindInstructionResult::kAborted);
Charlie Hu01b7e662021-09-13 14:51:36341 EXPECT_FALSE(pc_was_updated);
342 ASSERT_EQ(current_instruction, instruction + 2);
343 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
344
345 EXPECT_EQ(100ul, thread_context.arm_r0);
346 EXPECT_EQ(101ul, thread_context.arm_r1);
347 EXPECT_EQ(102ul, thread_context.arm_r2);
348 EXPECT_EQ(103ul, thread_context.arm_r3);
349 EXPECT_EQ(104ul, thread_context.arm_r4);
350 EXPECT_EQ(105ul, thread_context.arm_r5);
351 EXPECT_EQ(106ul, thread_context.arm_r6);
352 EXPECT_EQ(107ul, thread_context.arm_r7);
353 EXPECT_EQ(108ul, thread_context.arm_r8);
354 EXPECT_EQ(109ul, thread_context.arm_r9);
355 EXPECT_EQ(110ul, thread_context.arm_r10);
356 EXPECT_EQ(111ul, thread_context.arm_fp);
357 EXPECT_EQ(112ul, thread_context.arm_ip);
358 EXPECT_EQ(113ul, thread_context.arm_lr);
359 EXPECT_EQ(114ul, thread_context.arm_pc);
360}
361
Charlie Hu82c2ed352021-09-14 17:58:55362TEST(ChromeAndroidUnwindInstructionTest, TestRefuseToUnwind) {
363 RegisterContext thread_context = {};
364
365 const uint8_t instruction[] = {0b10000000, 0b0};
366 const uint8_t* current_instruction = instruction;
367
368 bool pc_was_updated = false;
369 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
370 &thread_context),
371 UnwindInstructionResult::kAborted);
372 EXPECT_FALSE(pc_was_updated);
373 ASSERT_EQ(current_instruction, instruction + 2);
374}
375
Charlie Hud5c14032021-08-26 21:45:59376TEST(ChromeAndroidUnwindInstructionTest,
377 TestPopRegistersIncludingR14MinRegisters) {
378 RegisterContext thread_context = {};
379
380 thread_context.arm_r0 = 100;
381 thread_context.arm_r1 = 101;
382 thread_context.arm_r2 = 102;
383 thread_context.arm_r3 = 103;
384 thread_context.arm_r4 = 104;
385 thread_context.arm_r5 = 105;
386 thread_context.arm_r6 = 106;
387 thread_context.arm_r7 = 107;
388 thread_context.arm_r8 = 108;
389 thread_context.arm_r9 = 109;
390 thread_context.arm_r10 = 110;
391 thread_context.arm_fp = 111;
392 thread_context.arm_ip = 112;
393 thread_context.arm_lr = 113;
394
395 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
396 // r14 = lr
397 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
398
399 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
400 const uint8_t instruction = 0b10101000;
401 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36402 bool pc_was_updated = false;
403 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
404 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55405 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36406 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59407 ASSERT_EQ(current_instruction, &instruction + 1);
408 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 2), thread_context.arm_sp);
409
410 EXPECT_EQ(100ul, thread_context.arm_r0);
411 EXPECT_EQ(101ul, thread_context.arm_r1);
412 EXPECT_EQ(102ul, thread_context.arm_r2);
413 EXPECT_EQ(103ul, thread_context.arm_r3);
414 EXPECT_EQ(1ul, thread_context.arm_r4);
415 EXPECT_EQ(105ul, thread_context.arm_r5);
416 EXPECT_EQ(106ul, thread_context.arm_r6);
417 EXPECT_EQ(107ul, thread_context.arm_r7);
418 EXPECT_EQ(108ul, thread_context.arm_r8);
419 EXPECT_EQ(109ul, thread_context.arm_r9);
420 EXPECT_EQ(110ul, thread_context.arm_r10);
421 EXPECT_EQ(111ul, thread_context.arm_fp);
422 EXPECT_EQ(112ul, thread_context.arm_ip);
423 EXPECT_EQ(2ul, thread_context.arm_lr);
424}
425
426TEST(ChromeAndroidUnwindInstructionTest,
427 TestPopRegistersIncludingR14MidRegisters) {
428 RegisterContext thread_context = {};
429
430 thread_context.arm_r0 = 100;
431 thread_context.arm_r1 = 101;
432 thread_context.arm_r2 = 102;
433 thread_context.arm_r3 = 103;
434 thread_context.arm_r4 = 104;
435 thread_context.arm_r5 = 105;
436 thread_context.arm_r6 = 106;
437 thread_context.arm_r7 = 107;
438 thread_context.arm_r8 = 108;
439 thread_context.arm_r9 = 109;
440 thread_context.arm_r10 = 110;
441 thread_context.arm_fp = 111;
442 thread_context.arm_ip = 112;
443 thread_context.arm_lr = 113;
444
445 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
446 // r14 = lr
447 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
448
449 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
450 const uint8_t instruction = 0b10101100; // Pop r4-r8, r14.
451 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36452 bool pc_was_updated = false;
453 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
454 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55455 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36456 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59457 ASSERT_EQ(current_instruction, &instruction + 1);
458 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 6), thread_context.arm_sp);
459
460 EXPECT_EQ(100ul, thread_context.arm_r0);
461 EXPECT_EQ(101ul, thread_context.arm_r1);
462 EXPECT_EQ(102ul, thread_context.arm_r2);
463 EXPECT_EQ(103ul, thread_context.arm_r3);
464 EXPECT_EQ(1ul, thread_context.arm_r4);
465 EXPECT_EQ(2ul, thread_context.arm_r5);
466 EXPECT_EQ(3ul, thread_context.arm_r6);
467 EXPECT_EQ(4ul, thread_context.arm_r7);
468 EXPECT_EQ(5ul, thread_context.arm_r8);
469 EXPECT_EQ(109ul, thread_context.arm_r9);
470 EXPECT_EQ(110ul, thread_context.arm_r10);
471 EXPECT_EQ(111ul, thread_context.arm_fp);
472 EXPECT_EQ(112ul, thread_context.arm_ip);
473 EXPECT_EQ(6ul, thread_context.arm_lr);
474}
475
476TEST(ChromeAndroidUnwindInstructionTest,
477 TestPopRegistersIncludingR14MaxRegisters) {
478 RegisterContext thread_context = {};
479
480 thread_context.arm_r0 = 100;
481 thread_context.arm_r1 = 101;
482 thread_context.arm_r2 = 102;
483 thread_context.arm_r3 = 103;
484 thread_context.arm_r4 = 104;
485 thread_context.arm_r5 = 105;
486 thread_context.arm_r6 = 106;
487 thread_context.arm_r7 = 107;
488 thread_context.arm_r8 = 108;
489 thread_context.arm_r9 = 109;
490 thread_context.arm_r10 = 110;
491 thread_context.arm_fp = 111;
492 thread_context.arm_ip = 112;
493 thread_context.arm_lr = 113;
494
495 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
496 // r14 = lr
497 const uintptr_t stack[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
498
499 thread_context.arm_sp = reinterpret_cast<uintptr_t>(&stack[0]);
500 const uint8_t instruction = 0b10101111; // Pop r4 - r11, r14.
501 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36502 bool pc_was_updated = false;
503 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
504 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55505 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36506 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59507 ASSERT_EQ(current_instruction, &instruction + 1);
508 EXPECT_EQ(reinterpret_cast<uintptr_t>(&stack[0] + 9), thread_context.arm_sp);
509
510 EXPECT_EQ(100ul, thread_context.arm_r0);
511 EXPECT_EQ(101ul, thread_context.arm_r1);
512 EXPECT_EQ(102ul, thread_context.arm_r2);
513 EXPECT_EQ(103ul, thread_context.arm_r3);
514 EXPECT_EQ(1ul, thread_context.arm_r4);
515 EXPECT_EQ(2ul, thread_context.arm_r5);
516 EXPECT_EQ(3ul, thread_context.arm_r6);
517 EXPECT_EQ(4ul, thread_context.arm_r7);
518 EXPECT_EQ(5ul, thread_context.arm_r8);
519 EXPECT_EQ(6ul, thread_context.arm_r9);
520 EXPECT_EQ(7ul, thread_context.arm_r10);
521 EXPECT_EQ(8ul, thread_context.arm_fp);
522 EXPECT_EQ(112ul, thread_context.arm_ip);
523 EXPECT_EQ(9ul, thread_context.arm_lr);
524}
525
526TEST(ChromeAndroidUnwindInstructionTest, TestPopRegistersIncludingR14Overflow) {
527 RegisterContext thread_context = {};
528
529 thread_context.arm_r0 = 100;
530 thread_context.arm_r1 = 101;
531 thread_context.arm_r2 = 102;
532 thread_context.arm_r3 = 103;
533 thread_context.arm_r4 = 104;
534 thread_context.arm_r5 = 105;
535 thread_context.arm_r6 = 106;
536 thread_context.arm_r7 = 107;
537 thread_context.arm_r8 = 108;
538 thread_context.arm_r9 = 109;
539 thread_context.arm_r10 = 110;
540 thread_context.arm_fp = 111;
541 thread_context.arm_ip = 112;
542 thread_context.arm_lr = 113;
543
544 // Popping r4 - r[4 + nnn], r14, at most 9 registers.
545 // r14 = lr
546 thread_context.arm_sp = 0xffffffff;
547 const uint8_t instruction = 0b10101111; // Pop r4 - r11, r14.
548 const uint8_t* current_instruction = &instruction;
Charlie Hu01b7e662021-09-13 14:51:36549 bool pc_was_updated = false;
550 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
551 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55552 UnwindInstructionResult::kAborted);
Charlie Hu01b7e662021-09-13 14:51:36553 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59554 ASSERT_EQ(current_instruction, &instruction + 1);
555 EXPECT_EQ(0xffffffff, thread_context.arm_sp);
556
557 EXPECT_EQ(100ul, thread_context.arm_r0);
558 EXPECT_EQ(101ul, thread_context.arm_r1);
559 EXPECT_EQ(102ul, thread_context.arm_r2);
560 EXPECT_EQ(103ul, thread_context.arm_r3);
561 EXPECT_EQ(104ul, thread_context.arm_r4);
562 EXPECT_EQ(105ul, thread_context.arm_r5);
563 EXPECT_EQ(106ul, thread_context.arm_r6);
564 EXPECT_EQ(107ul, thread_context.arm_r7);
565 EXPECT_EQ(108ul, thread_context.arm_r8);
566 EXPECT_EQ(109ul, thread_context.arm_r9);
567 EXPECT_EQ(110ul, thread_context.arm_r10);
568 EXPECT_EQ(111ul, thread_context.arm_fp);
569 EXPECT_EQ(112ul, thread_context.arm_ip);
570 EXPECT_EQ(113ul, thread_context.arm_lr);
571}
572
573TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementMinValue) {
574 RegisterContext thread_context = {};
575 thread_context.arm_sp = 0x10000000;
576
577 const uint8_t increment_0[] = {
578 0b10110010,
579 0b00000000,
580 };
581 const uint8_t* current_instruction = &increment_0[0];
Charlie Hu01b7e662021-09-13 14:51:36582 bool pc_was_updated = false;
583 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
584 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55585 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36586 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59587 ASSERT_EQ(current_instruction, increment_0 + sizeof(increment_0));
588 // vsp + 0x204 + (0 << 2)
589 // = vsp + 0x204
590 EXPECT_EQ(0x10000204ul, thread_context.arm_sp);
591}
592
593TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementMidValue) {
594 RegisterContext thread_context = {};
595 thread_context.arm_sp = 0x10000000;
596
597 const uint8_t increment_4[] = {
598 0b10110010,
599 0b00000100,
600 };
601 const uint8_t* current_instruction = &increment_4[0];
602
603 // vsp + 0x204 + (4 << 2)
604 // = vsp + 0x204 + 0x10
605 // = vsp + 0x214
Charlie Hu01b7e662021-09-13 14:51:36606 bool pc_was_updated = false;
607 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
608 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55609 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36610 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59611 ASSERT_EQ(current_instruction, increment_4 + sizeof(increment_4));
612 EXPECT_EQ(0x10000214ul, thread_context.arm_sp);
613}
614
615TEST(ChromeAndroidUnwindInstructionTest,
616 TestBigStackPointerIncrementLargeValue) {
617 RegisterContext thread_context = {};
618 thread_context.arm_sp = 0x10000000;
619
620 const uint8_t increment_128[] = {
621 0b10110010,
622 0b10000000,
623 0b00000001,
624 };
625 const uint8_t* current_instruction = &increment_128[0];
626 // vsp + 0x204 + (128 << 2)
627 // = vsp + 0x204 + 512
628 // = vsp + 0x204 + 0x200
629 // = vsp + 0x404
Charlie Hu01b7e662021-09-13 14:51:36630 bool pc_was_updated = false;
631 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
632 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55633 UnwindInstructionResult::kInstructionPending);
Charlie Hu01b7e662021-09-13 14:51:36634 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59635 ASSERT_EQ(current_instruction, increment_128 + sizeof(increment_128));
636 EXPECT_EQ(0x10000404ul, thread_context.arm_sp);
637}
638
639TEST(ChromeAndroidUnwindInstructionTest, TestBigStackPointerIncrementOverflow) {
640 RegisterContext thread_context = {};
641 thread_context.arm_sp = 0xffffffff;
642
643 const uint8_t increment_overflow[] = {
644 0b10110010,
645 0b10000000,
646 0b00000001,
647 }; // ULEB128 = 128
648 const uint8_t* current_instruction = &increment_overflow[0];
Charlie Hu01b7e662021-09-13 14:51:36649 bool pc_was_updated = false;
650 ASSERT_EQ(ExecuteUnwindInstruction(current_instruction, pc_was_updated,
651 &thread_context),
Charlie Hu82c2ed352021-09-14 17:58:55652 UnwindInstructionResult::kAborted);
Charlie Hu01b7e662021-09-13 14:51:36653 EXPECT_FALSE(pc_was_updated);
Charlie Hud5c14032021-08-26 21:45:59654 ASSERT_EQ(current_instruction,
655 increment_overflow + sizeof(increment_overflow));
656 EXPECT_EQ(0xfffffffful, thread_context.arm_sp);
657}
658
Charlie Hue0a13a72021-09-24 21:57:39659TEST(ChromeUnwinderAndroidV2Test,
Charlie Huf36b2f62021-09-01 22:31:20660 TestFunctionOffsetTableLookupExactMatchingOffset) {
Charlie Huf36b2f62021-09-01 22:31:20661 const uint8_t function_offset_table[] = {
662 // Function 1: [(130, 2), (128, 3), (0, 4)]
663 // offset = 130
664 0b10000010,
665 0b00000001,
666 // unwind index = 2
667 0b00000010,
668 // offset = 128
669 0b10000000,
670 0b00000001,
671 // unwind index = 3
672 0b00000011,
673 // offset = 0
674 0b00000000,
675 // unwind index = 4
676 0b00000100,
677 };
678
Charlie Hu78e00402021-10-13 06:10:43679 EXPECT_EQ(3ul, GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(
680 &function_offset_table[0],
681 /* instruction_offset_from_function_start */ 128));
Charlie Huf36b2f62021-09-01 22:31:20682}
683
Charlie Hue0a13a72021-09-24 21:57:39684TEST(ChromeUnwinderAndroidV2Test,
Charlie Huf36b2f62021-09-01 22:31:20685 TestFunctionOffsetTableLookupNonExactMatchingOffset) {
Charlie Huf36b2f62021-09-01 22:31:20686 const uint8_t function_offset_table[] = {
687 // Function 1: [(130, 2), (128, 3), (0, 4)]
688 // offset = 130
689 0b10000010,
690 0b00000001,
691 // unwind index = 2
692 0b00000010,
693 // offset = 128
694 0b10000000,
695 0b00000001,
696 // unwind index = 3
697 0b00000011,
698 // offset = 0
699 0b00000000,
700 // unwind index = 4
701 0b00000100,
702 };
703
Charlie Hu78e00402021-10-13 06:10:43704 EXPECT_EQ(3ul, GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(
705 &function_offset_table[0],
706 /* instruction_offset_from_function_start */ 129));
Charlie Huf36b2f62021-09-01 22:31:20707}
708
Charlie Hue0a13a72021-09-24 21:57:39709TEST(ChromeUnwinderAndroidV2Test, TestFunctionOffsetTableLookupZeroOffset) {
Charlie Huf36b2f62021-09-01 22:31:20710 const uint8_t function_offset_table[] = {
711 // Function 1: [(130, 2), (128, 3), (0, 4)]
712 // offset = 130
713 0b10000010,
714 0b00000001,
715 // unwind index = 2
716 0b00000010,
717 // offset = 128
718 0b10000000,
719 0b00000001,
720 // unwind index = 3
721 0b00000011,
722 // offset = 0
723 0b00000000,
724 // unwind index = 4
725 0b00000100,
726 };
727
Charlie Hu78e00402021-10-13 06:10:43728 EXPECT_EQ(4ul, GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(
729 &function_offset_table[0],
730 /* instruction_offset_from_function_start */ 0));
Charlie Huf36b2f62021-09-01 22:31:20731}
732
Charlie Hue0a13a72021-09-24 21:57:39733TEST(ChromeUnwinderAndroidV2Test, TestAddressTableLookupEntryInPage) {
Charlie Hu235c6b72021-09-13 20:50:01734 const uint32_t page_start_instructions[] = {0, 2};
735 const FunctionTableEntry function_offset_table_indices[] = {
736 // Page 0
737 {
738 /* function_start_address_page_instruction_offset */ 0,
739 /* function_offset_table_byte_index */ 20,
740 },
741 {
742 /* function_start_address_page_instruction_offset */ 4,
743 /* function_offset_table_byte_index */ 40,
744 },
745 // Page 1
746 {
747 /* function_start_address_page_instruction_offset */ 6,
748 /* function_offset_table_byte_index */ 70,
749 },
750 };
751
752 {
753 const uint32_t page_number = 0;
754 const uint32_t page_instruction_offset = 4;
755 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
756 page_start_instructions, function_offset_table_indices,
757 /* instruction_offset */ (page_instruction_offset << 1) +
758 (page_number << 17));
759 ASSERT_NE(absl::nullopt, entry_found);
760 EXPECT_EQ(0, entry_found->instruction_offset_from_function_start);
761 EXPECT_EQ(40ul, entry_found->function_offset_table_byte_index);
762 }
763
764 {
765 const uint32_t page_number = 0;
766 const uint32_t page_instruction_offset = 50;
767 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
768 page_start_instructions, function_offset_table_indices,
769 /* instruction_offset */ (page_instruction_offset << 1) +
770 (page_number << 17));
771 ASSERT_NE(absl::nullopt, entry_found);
772 EXPECT_EQ(46, entry_found->instruction_offset_from_function_start);
773 EXPECT_EQ(40ul, entry_found->function_offset_table_byte_index);
774 }
775
776 // Lookup last instruction in last function.
777 {
778 const uint32_t page_number = 1;
779 const uint32_t page_instruction_offset = 0xffff;
780 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
781 page_start_instructions, function_offset_table_indices,
782 /* instruction_offset */ (page_instruction_offset << 1) +
783 (page_number << 17));
784 ASSERT_NE(absl::nullopt, entry_found);
785 // 0xffff - 6 = 0xfff9.
786 EXPECT_EQ(0xfff9, entry_found->instruction_offset_from_function_start);
787 EXPECT_EQ(70ul, entry_found->function_offset_table_byte_index);
788 }
789}
790
Charlie Hue0a13a72021-09-24 21:57:39791TEST(ChromeUnwinderAndroidV2Test, TestAddressTableLookupEmptyPage) {
Charlie Hu235c6b72021-09-13 20:50:01792 const uint32_t page_start_instructions[] = {0, 1, 1};
793 const FunctionTableEntry function_offset_table_indices[] = {
794 // Page 0
795 {
796 /* function_start_address_page_instruction_offset */ 0,
797 /* function_offset_table_byte_index */ 20,
798 },
799 // Page 1 is empty
800 // Page 2
801 {
802 /* function_start_address_page_instruction_offset */ 6,
803 /* function_offset_table_byte_index */ 70,
804 },
805 };
806
807 const uint32_t page_number = 1;
808 const uint32_t page_instruction_offset = 4;
809 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
810 page_start_instructions, function_offset_table_indices,
811 /* instruction_offset */ (page_instruction_offset << 1) +
812 (page_number << 17));
813 ASSERT_NE(absl::nullopt, entry_found);
814 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
815 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
816}
817
Charlie Hue0a13a72021-09-24 21:57:39818TEST(ChromeUnwinderAndroidV2Test,
Charlie Hu235c6b72021-09-13 20:50:01819 TestAddressTableLookupInvalidIntructionOffset) {
820 const uint32_t page_start_instructions[] = {0, 1};
821 const FunctionTableEntry function_offset_table_indices[] = {
822 // Page 0
823 // This function spans from page 0 offset 0 to page 1 offset 5.
824 {
825 /* function_start_address_page_instruction_offset */ 0,
826 /* function_offset_table_byte_index */ 20,
827 },
828 // Page 1
829 {
830 /* function_start_address_page_instruction_offset */ 6,
831 /* function_offset_table_byte_index */ 70,
832 },
833 };
834
835 // Instruction offset lies after last page on page table.
836 {
837 const uint32_t page_number = 50;
838 const uint32_t page_instruction_offset = 6;
839 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
840 page_start_instructions, function_offset_table_indices,
841 /* instruction_offset */ (page_instruction_offset << 1) +
842 (page_number << 17));
843 ASSERT_EQ(absl::nullopt, entry_found);
844 }
845 {
846 const uint32_t page_number = 2;
847 const uint32_t page_instruction_offset = 0;
848 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
849 page_start_instructions, function_offset_table_indices,
850 /* instruction_offset */ (page_instruction_offset << 1) +
851 (page_number << 17));
852 ASSERT_EQ(absl::nullopt, entry_found);
853 }
854}
855
Charlie Hue0a13a72021-09-24 21:57:39856TEST(ChromeUnwinderAndroidV2Test,
Charlie Hu235c6b72021-09-13 20:50:01857 TestAddressTableLookupOnSecondPageOfFunctionSpanningPageBoundary) {
858 const uint32_t page_start_instructions[] = {0, 1, 2};
859 const FunctionTableEntry function_offset_table_indices[] = {
860 // Page 0
861 {
862 /* function_start_address_page_instruction_offset */ 0,
863 /* function_offset_table_byte_index */ 20,
864 },
865 // Page 1
866 {
867 /* function_start_address_page_instruction_offset */ 6,
868 /* function_offset_table_byte_index */ 70,
869 },
870 // Page 2
871 {
872 /* function_start_address_page_instruction_offset */ 10,
873 /* function_offset_table_byte_index */ 80,
874 }};
875
876 const uint32_t page_number = 1;
877 const uint32_t page_instruction_offset = 4;
878 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
879 page_start_instructions, function_offset_table_indices,
880 /* instruction_offset */ (page_instruction_offset << 1) +
881 (page_number << 17));
882 ASSERT_NE(absl::nullopt, entry_found);
883 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
884 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
885}
886
Charlie Hue0a13a72021-09-24 21:57:39887TEST(ChromeUnwinderAndroidV2Test,
Charlie Hu235c6b72021-09-13 20:50:01888 TestAddressTableLookupWithinFunctionSpanningMultiplePages) {
889 const uint32_t page_start_instructions[] = {0, 1, 1, 1};
890 const FunctionTableEntry function_offset_table_indices[] = {
891 // Page 0
892 // This function spans from page 0 offset 0 to page 3 offset 5.
893 {
894 /* function_start_address_page_instruction_offset */ 0,
895 /* function_offset_table_byte_index */ 20,
896 },
897 // Page 1 is empty
898 // Page 2 is empty
899 // Page 3
900 {
901 /* function_start_address_page_instruction_offset */ 6,
902 /* function_offset_table_byte_index */ 70,
903 },
904 };
905
906 {
907 const uint32_t page_number = 0;
908 const uint32_t page_instruction_offset = 4;
909 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
910 page_start_instructions, function_offset_table_indices,
911 /* instruction_offset */ (page_instruction_offset << 1) +
912 (page_number << 17));
913 ASSERT_NE(absl::nullopt, entry_found);
914 EXPECT_EQ(0x4, entry_found->instruction_offset_from_function_start);
915 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
916 }
917 {
918 const uint32_t page_number = 1;
919 const uint32_t page_instruction_offset = 4;
920 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
921 page_start_instructions, function_offset_table_indices,
922 /* instruction_offset */ (page_instruction_offset << 1) +
923 (page_number << 17));
924 ASSERT_NE(absl::nullopt, entry_found);
925 EXPECT_EQ(0x10004, entry_found->instruction_offset_from_function_start);
926 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
927 }
928 {
929 const uint32_t page_number = 2;
930 const uint32_t page_instruction_offset = 4;
931 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
932 page_start_instructions, function_offset_table_indices,
933 /* instruction_offset */ (page_instruction_offset << 1) +
934 (page_number << 17));
935 ASSERT_NE(absl::nullopt, entry_found);
936 EXPECT_EQ(0x20004, entry_found->instruction_offset_from_function_start);
937 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
938 }
939 {
940 const uint32_t page_number = 3;
941 const uint32_t page_instruction_offset = 4;
942 const auto entry_found = GetFunctionTableIndexFromInstructionOffset(
943 page_start_instructions, function_offset_table_indices,
944 /* instruction_offset */ (page_instruction_offset << 1) +
945 (page_number << 17));
946 ASSERT_NE(absl::nullopt, entry_found);
947 EXPECT_EQ(0x30004, entry_found->instruction_offset_from_function_start);
948 EXPECT_EQ(20ul, entry_found->function_offset_table_byte_index);
949 }
950}
Charlie Hu78e00402021-10-13 06:10:43951
952class TestModule : public ModuleCache::Module {
953 public:
954 TestModule(uintptr_t base_address,
955 size_t size,
956 const std::string& build_id = "TestModule")
957 : base_address_(base_address), size_(size), build_id_(build_id) {}
958
959 uintptr_t GetBaseAddress() const override { return base_address_; }
960 std::string GetId() const override { return build_id_; }
961 FilePath GetDebugBasename() const override { return FilePath(); }
962 size_t GetSize() const override { return size_; }
963 bool IsNative() const override { return true; }
964
965 private:
966 const uintptr_t base_address_;
967 const size_t size_;
968 const std::string build_id_;
969};
970
971// Utility function to add a single native module during test setup. Returns
972// a pointer to the provided module.
973const ModuleCache::Module* AddNativeModule(
974 ModuleCache* cache,
975 std::unique_ptr<const ModuleCache::Module> module) {
976 const ModuleCache::Module* module_ptr = module.get();
977 cache->AddCustomNativeModule(std::move(module));
978 return module_ptr;
979}
980
981TEST(ChromeUnwinderAndroidV2Test, CanUnwindFrom) {
982 const uint32_t page_table[] = {0};
983 const FunctionTableEntry function_table[] = {{0, 0}};
984 const uint8_t function_offset_table[] = {0};
985 const uint8_t unwind_instruction_table[] = {0};
986 auto dummy_unwind_info = ChromeUnwindInfoAndroid{
987 make_span(unwind_instruction_table, 1ul),
988 make_span(function_offset_table, 1ul),
989 make_span(function_table, 1ul),
990 make_span(page_table, 1ul),
991 };
992
993 auto chrome_module =
994 std::make_unique<TestModule>(0x1000, 0x500, "ChromeModule");
995 auto non_chrome_module =
996 std::make_unique<TestModule>(0x2000, 0x500, "OtherModule");
997
998 ModuleCache module_cache;
999 ChromeUnwinderAndroidV2 unwinder(dummy_unwind_info,
1000 chrome_module->GetBaseAddress(),
1001 /* text_section_start_address */
1002 chrome_module->GetBaseAddress() + 4);
1003 unwinder.Initialize(&module_cache);
1004
1005 EXPECT_TRUE(unwinder.CanUnwindFrom({0x1100, chrome_module.get()}));
1006 EXPECT_TRUE(unwinder.CanUnwindFrom({0x1000, chrome_module.get()}));
1007 EXPECT_FALSE(unwinder.CanUnwindFrom({0x2100, non_chrome_module.get()}));
1008 EXPECT_FALSE(unwinder.CanUnwindFrom({0x400, nullptr}));
1009}
1010
1011void ExpectFramesEq(const std::vector<Frame>& actual,
1012 const std::vector<Frame>& expected) {
1013 EXPECT_EQ(actual.size(), expected.size());
1014 if (actual.size() != expected.size())
1015 return;
1016
1017 for (size_t i = 0; i < actual.size(); i++) {
1018 EXPECT_EQ(actual[i].module, expected[i].module);
1019 EXPECT_EQ(actual[i].instruction_pointer, expected[i].instruction_pointer);
1020 }
1021}
1022
1023TEST(ChromeUnwinderAndroidV2Test, TryUnwind) {
1024 const uint32_t page_table[] = {0, 2};
1025 const size_t number_of_pages = base::size(page_table);
1026 const size_t page_size = 1 << 17;
1027
1028 const FunctionTableEntry function_table[] = {
1029 // Page 0.
1030 {0, 0}, // Function 0.
1031 {0x10, 4}, // Function 1. The function to unwind 2 times.
1032 // Page 1.
1033 {0x5, 8}, // Function 2.
1034 {0x20, 12}, // Function 3.
1035 };
1036 const uint8_t function_offset_table[] = {
1037 // Function 0.
1038 0x2,
1039 0,
1040 0x0,
1041 2,
1042 // Function 1.
1043 0x7f,
1044 0,
1045 0x0,
1046 2,
1047 // Function 2.
1048 0x78,
1049 0,
1050 0x0,
1051 2,
1052 // Function 3.
1053 0x2,
1054 0,
1055 0x0,
1056 2,
1057 };
1058 const uint8_t unwind_instruction_table[] = {
1059 // Offset 0: Pop r14 from stack top.
1060 0b10000100,
1061 0b00000000,
1062 // Offset 2: COMPLETE.
1063 0b10110000,
1064 };
1065
1066 auto unwind_info = ChromeUnwindInfoAndroid{
1067 make_span(unwind_instruction_table, base::size(unwind_instruction_table)),
1068 make_span(function_offset_table, base::size(function_offset_table)),
1069 make_span(function_table, base::size(function_table)),
1070 make_span(page_table, base::size(page_table)),
1071 };
1072
1073 ModuleCache module_cache;
1074 const ModuleCache::Module* chrome_module = AddNativeModule(
1075 &module_cache, std::make_unique<TestModule>(
1076 0x1000, number_of_pages * page_size, "ChromeModule"));
1077
1078 uintptr_t text_section_start_address = 0x1100;
1079 ChromeUnwinderAndroidV2 unwinder(unwind_info, chrome_module->GetBaseAddress(),
1080 text_section_start_address);
1081
1082 unwinder.Initialize(&module_cache);
1083
1084 // Both first_pc and second_pc lie in Function 1's address range.
1085 uintptr_t first_pc = text_section_start_address + 0x20;
1086 uintptr_t second_pc = text_section_start_address + page_size + 0x4;
1087 // third_pc lies outside chrome_module's address range.
1088 uintptr_t third_pc = text_section_start_address + 3 * page_size;
1089
1090 const std::vector<uintptr_t> stack_memory = {
1091 third_pc,
1092 0xFFFF,
1093 };
1094 uintptr_t stack_top =
1095 reinterpret_cast<uintptr_t>(stack_memory.data() + stack_memory.size());
1096
1097 std::vector<Frame> unwound_frames = {{first_pc, chrome_module}};
1098 RegisterContext context;
1099 RegisterContextInstructionPointer(&context) = first_pc;
1100 RegisterContextStackPointer(&context) =
1101 reinterpret_cast<uintptr_t>(stack_memory.data());
1102 context.arm_lr = second_pc;
1103
Charlie Hua1d07b922021-11-02 16:55:131104 EXPECT_EQ(UnwindResult::kUnrecognizedFrame,
Charlie Hu78e00402021-10-13 06:10:431105 unwinder.TryUnwind(&context, stack_top, &unwound_frames));
1106 ExpectFramesEq(std::vector<Frame>({{first_pc, chrome_module},
1107 {second_pc, chrome_module},
1108 {third_pc, nullptr}}),
1109 unwound_frames);
1110}
1111
Charlie Hud5c14032021-08-26 21:45:591112} // namespace base