1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "callstack_test.h"
17
18 using namespace testing::ext;
19 namespace OHOS {
20 namespace Developtools {
21 namespace HiPerf {
22 class CallStackTest : public testing::Test {
23 public:
24 static void SetUpTestCase(void);
25 static void TearDownTestCase(void);
26 void SetUp();
27 void TearDown();
28 std::default_random_engine rnd_;
29 };
30
SetUpTestCase()31 void CallStackTest::SetUpTestCase()
32 {
33 DebugLogger::GetInstance()->Reset();
34 DebugLogger::GetInstance()->OpenLog(DEFAULT_UT_LOG_DIR + "CallStackTest.txt");
35 }
36
TearDownTestCase()37 void CallStackTest::TearDownTestCase()
38 {
39 DebugLogger::GetInstance()->RestoreLog();
40 }
41
SetUp()42 void CallStackTest::SetUp() {}
43
TearDown()44 void CallStackTest::TearDown() {}
45
46 /**
47 * @tc.name: ExpandCallStack
48 * @tc.desc:
49 * @tc.type: FUNC
50 */
51 HWTEST_F(CallStackTest, ExpendCallStackEmpty, TestSize.Level1)
52 {
53 /*
54 3 2 1
55 cache A -> B -> C
56 new C
57 expand A -> B -> C
58 */
59 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
60 CallStack callStack;
61
62 std::vector<DfxFrame> stack1 = {
63 {0x1u, 0x1u},
64 {0x2u, 0x2u},
65 {0x3u, 0x3u},
66 };
67 std::vector<DfxFrame> stack2 = {};
68
69 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
70 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
71 ASSERT_NE(stack1, stack2);
72 }
73
74 /**
75 * @tc.name: ExpandCallStack
76 * @tc.desc:
77 * @tc.type: FUNC
78 */
79 HWTEST_F(CallStackTest, ExpendCallStackC, TestSize.Level1)
80 {
81 /*
82 3 2 1
83 cache A -> B -> C
84 new C
85 expand A -> B -> C
86 */
87 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
88 CallStack callStack;
89
90 std::vector<DfxFrame> stack1 = {
91 {0x1u, 0x1u},
92 {0x2u, 0x2u},
93 {0x3u, 0x3u},
94 };
95 std::vector<DfxFrame> stack2 = {
96 {0x1u, 0x1u},
97 };
98
99 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
100 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 2u);
101 ASSERT_EQ(stack1, stack2);
102 }
103
104 /**
105 * @tc.name: ExpandCallStack
106 * @tc.desc:
107 * @tc.type: FUNC
108 */
109 HWTEST_F(CallStackTest, ExpendCallStackBC, TestSize.Level1)
110 {
111 /*
112 3 2 1
113 cache A -> B -> C
114 new B -> C
115 expand A -> B -> C
116 */
117 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
118 CallStack callStack;
119
120 std::vector<DfxFrame> stack1 = {
121 {0x1u, 0x1u},
122 {0x2u, 0x2u},
123 {0x3u, 0x3u},
124 };
125 std::vector<DfxFrame> stack2 = {
126 {0x1u, 0x1u},
127 {0x2u, 0x2u},
128 };
129
130 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
131 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u);
132 ASSERT_EQ(stack1, stack2);
133 }
134
135 /**
136 * @tc.name: ExpandCallStack
137 * @tc.desc:
138 * @tc.type: FUNC
139 */
140 HWTEST_F(CallStackTest, ExpendCallStackABC, TestSize.Level1)
141 {
142 /*
143 3 2 1
144 cache A -> B -> C
145 new A -> B -> C
146 expand A -> B -> C
147 */
148 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
149 CallStack callStack;
150
151 std::vector<DfxFrame> stack1 = {
152 {0x1u, 0x1u},
153 {0x2u, 0x2u},
154 {0x3u, 0x3u},
155 };
156 std::vector<DfxFrame> stack2 = {
157 {0x1u, 0x1u},
158 {0x2u, 0x2u},
159 {0x3u, 0x3u},
160 };
161
162 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
163 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
164 ASSERT_EQ(stack1, stack2);
165 }
166
167 /**
168 * @tc.name: ExpandCallStack
169 * @tc.desc:
170 * @tc.type: FUNC
171 */
172 HWTEST_F(CallStackTest, ExpendCallStackAB, TestSize.Level1)
173 {
174 /*
175 3 2 1
176 cache A -> B -> C
177 new A -> B
178 expand A -> B
179 */
180 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
181 CallStack callStack;
182
183 std::vector<DfxFrame> stack1 = {
184 {0x1u, 0x1u},
185 {0x2u, 0x2u},
186 {0x3u, 0x3u},
187 };
188 std::vector<DfxFrame> stack2 = {
189 {0x2u, 0x2u},
190 {0x3u, 0x3u},
191 };
192
193 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
194 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
195 ASSERT_NE(stack1, stack2);
196 }
197
198 /**
199 * @tc.name: ExpandCallStack
200 * @tc.desc:
201 * @tc.type: FUNC
202 */
203 HWTEST_F(CallStackTest, ExpendCallStackA, TestSize.Level1)
204 {
205 /*
206 3 2 1
207 cache A -> B -> C
208 new A
209 expand A
210 */
211 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
212 CallStack callStack;
213
214 std::vector<DfxFrame> stack1 = {
215 {0x1u, 0x1u},
216 {0x2u, 0x2u},
217 {0x3u, 0x3u},
218 };
219 std::vector<DfxFrame> stack2 = {
220 {0x3u, 0x3u},
221 };
222
223 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
224 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u);
225 ASSERT_NE(stack1, stack2);
226 }
227
228 /**
229 * @tc.name: ExpandCallStack
230 * @tc.desc:
231 * @tc.type: FUNC
232 */
233 HWTEST_F(CallStackTest, ExpendCallStackB, TestSize.Level1)
234 {
235 /*
236 3 2 1
237 cache A -> B -> C
238 new B
239 expand A -> B
240 */
241 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
242 CallStack callStack;
243
244 std::vector<DfxFrame> stack1 = {
245 {0x1u, 0x1u},
246 {0x2u, 0x2u},
247 {0x3u, 0x3u},
248 };
249 std::vector<DfxFrame> stack2 = {
250 {0x2u, 0x2u},
251 };
252 std::vector<DfxFrame> stack3 = {
253 {0x2u, 0x2u},
254 {0x3u, 0x3u},
255 };
256 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
257 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u);
258 ASSERT_NE(stack1, stack2);
259 ASSERT_EQ(stack3, stack2);
260 }
261
262 /**
263 * @tc.name: ExpandCallStack
264 * @tc.desc:
265 * @tc.type: FUNC
266 */
267 HWTEST_F(CallStackTest, ExpendCallStackB2, TestSize.Level1)
268 {
269 /*
270 3 2 1
271 cache A -> B -> C
272 new B
273 expand A -> B
274 */
275 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
276 CallStack callStack;
277
278 std::vector<DfxFrame> stack1 = {
279 {0x1u, 0x1u},
280 {0x2u, 0x2u},
281 {0x3u, 0x3u},
282 };
283 std::vector<DfxFrame> stack2 = {
284 {0x2u, 0x2u},
285 };
286 std::vector<DfxFrame> stack3 = {
287 {0x2u, 0x2u},
288 {0x3u, 0x3u},
289 };
290 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u);
291 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u);
292 ASSERT_NE(stack1, stack2);
293 ASSERT_NE(stack3, stack2);
294 }
295
296 /**
297 * @tc.name: ExpandCallStack
298 * @tc.desc:
299 * @tc.type: FUNC
300 */
301 HWTEST_F(CallStackTest, ExpendCallStackB0, TestSize.Level1)
302 {
303 /*
304 3 2 1
305 cache A -> B -> C
306 new B
307 expand A -> B
308 */
309 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
310 CallStack callStack;
311
312 std::vector<DfxFrame> stack1 = {
313 {0x1u, 0x1u},
314 {0x2u, 0x2u},
315 {0x3u, 0x3u},
316 };
317 std::vector<DfxFrame> stack2 = {
318 {0x2u, 0x2u},
319 };
320 std::vector<DfxFrame> stack3 = {
321 {0x2u, 0x2u},
322 {0x3u, 0x3u},
323 };
324 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 0), 0u);
325 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 0), 0u);
326 ASSERT_NE(stack1, stack2);
327 ASSERT_NE(stack3, stack2);
328 }
329
330 /**
331 * @tc.name: ExpandCallStack
332 * @tc.desc:
333 * @tc.type: FUNC
334 */
335 HWTEST_F(CallStackTest, ExpendCallStackBC2, TestSize.Level1)
336 {
337 /*
338 3 2 1
339 cache A -> B -> C
340 new B -> C
341 expand A -> B -> C
342 */
343 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
344 CallStack callStack;
345
346 std::vector<DfxFrame> stack1 = {
347 {0x1u, 0x1u},
348 {0x2u, 0x2u},
349 {0x3u, 0x3u},
350 };
351 std::vector<DfxFrame> stack2 = {
352 {0x1u, 0x1u},
353 {0x2u, 0x2u},
354 };
355
356 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u);
357 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 1u);
358 ASSERT_EQ(stack1, stack2);
359 }
360
361 /**
362 * @tc.name: ExpandCallStack
363 * @tc.desc:
364 * @tc.type: FUNC
365 */
366 HWTEST_F(CallStackTest, ExpendCallStackABCDE, TestSize.Level1)
367 {
368 /*
369 0. A -> B -> C -> E -> F
370 1. C -> E -> F
371 2. B -> C
372 3. A -> B -> C
373 4. B -> F -> F
374 */
375 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
376 CallStack callStack;
377
378 std::vector<DfxFrame> stackFull = {
379 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA},
380 };
381 std::vector<DfxFrame> stackBC = {
382 {0xC, 0xC},
383 {0xB, 0xB},
384 };
385 std::vector<DfxFrame> stackABC = {
386 {0xC, 0xC},
387 {0xB, 0xB},
388 {0xA, 0xA},
389 };
390 std::vector<DfxFrame> stackBFF = {
391 {0xF, 0xF},
392 {0xF, 0xF},
393 {0xB, 0xB},
394 };
395 std::vector<DfxFrame> stackBFF2 = {
396 {0xF, 0xF},
397 {0xF, 0xF},
398 {0xB, 0xB},
399 };
400
401 ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u);
402 ASSERT_EQ(callStack.ExpandCallStack(0, stackBC), 1u);
403 ASSERT_EQ(callStack.ExpandCallStack(0, stackABC), 0u);
404 ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF), 1u);
405
406 // use stackBFF
407 ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF2, 2), 1u);
408 }
409
410 /**
411 * @tc.name: ExpandCallStack
412 * @tc.desc:
413 * @tc.type: FUNC
414 */
415 HWTEST_F(CallStackTest, ExpendCallStackFailure, TestSize.Level1)
416 {
417 /*
418 0. A -> B -> C -> E -> F
419 1. C -> E -> F
420 2. B -> C
421 3. A -> B -> C
422 4. B -> F -> F
423 */
424 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
425 CallStack callStack;
426
427 std::vector<DfxFrame> stackFull = {
428 {0xC, 0xC},
429 {0xB, 0xB},
430 {0xA, 0xA},
431 };
432 std::vector<DfxFrame> stackDE = {
433 {0xE, 0xE},
434 {0xD, 0xD},
435 };
436
437 ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u);
438 ASSERT_EQ(callStack.ExpandCallStack(0, stackDE), 0u);
439 }
440
441 /**
442 * @tc.name: ExpandCallStack
443 * @tc.desc:
444 * @tc.type: FUNC
445 */
446 HWTEST_F(CallStackTest, ExpendCallStackTwoChance, TestSize.Level1)
447 {
448 /*
449 0. A -> B -> C -> E -> F
450 1. 2 -> C -> E -> F
451 2. C
452 */
453 ScopeDebugLevel tempLogLevel(LEVEL_MUCH);
454 CallStack callStack;
455
456 std::vector<DfxFrame> stack0 = {
457 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA},
458 };
459 std::vector<DfxFrame> stack1 = {
460 {0xE, 0xE},
461 {0xD, 0xD},
462 {0xC, 0xC},
463 {0x2, 0x2},
464 };
465 std::vector<DfxFrame> stackC = {
466 {0xC, 0xC},
467 };
468 std::vector<DfxFrame> stackC2 = {
469 {0xC, 0xC},
470 {0x2, 0x2},
471 };
472 ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u);
473 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
474 ASSERT_EQ(callStack.ExpandCallStack(0, stackC), 1u);
475 }
476
477 /**
478 * @tc.name: ExpandCallStack
479 * @tc.desc:
480 * @tc.type: FUNC
481 */
482 HWTEST_F(CallStackTest, ExpendCallStackFullCache, TestSize.Level1)
483 {
484 CallStack callStack;
485 for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) {
486 std::vector<DfxFrame> stack = {{rnd_(), rnd_()}};
487 callStack.ExpandCallStack(0, stack);
488 }
489 for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) {
490 std::vector<DfxFrame> stack = {{rnd_(), rnd_()}};
491 callStack.ExpandCallStack(0, stack);
492 }
493 EXPECT_EQ(callStack.cachedCallFramesMap_[0].size(), MAX_CALL_FRAME_EXPAND_CACHE_SIZE);
494 }
495
496 /**
497 * @tc.name: ExpandCallStack
498 * @tc.desc:
499 * @tc.type: FUNC
500 */
501 HWTEST_F(CallStackTest, ExpendCallStackSmall, TestSize.Level1)
502 {
503 CallStack callStack;
504 std::vector<DfxFrame> stack0 = {};
505 std::vector<DfxFrame> stack1 = {{0x1, 0x1}};
506 std::vector<DfxFrame> stack2 = {{0x1, 0x1}, {0x2, 0x2}};
507 ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u);
508 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
509 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
510 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u);
511 }
512
513 /**
514 * @tc.name: ExpandCallStack
515 * @tc.desc:
516 * @tc.type: FUNC
517 */
518 HWTEST_F(CallStackTest, ExpendCallStackLimit, TestSize.Level1)
519 {
520 /*
521 3 2 1 0
522 cache A -> B -> C
523 stack2 C
524 expand C
525
526 stack3 B -> C
527 expand A -> B -> C
528
529 stack4 C -> D
530 expand C
531 */
532 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
533 CallStack callStack;
534
535 std::vector<DfxFrame> stack1 = {
536 {0x1u, 0x1u},
537 {0x2u, 0x2u},
538 {0x3u, 0x3u},
539 };
540 std::vector<DfxFrame> stack2 = {
541 {0x1u, 0x1u},
542 };
543 std::vector<DfxFrame> stack3 = {
544 {0x1u, 0x1u},
545 {0x2u, 0x2u},
546 };
547 std::vector<DfxFrame> stack4 = {
548 {0x0u, 0x0u},
549 {0x1u, 0x1u},
550 };
551
552 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2u), 0u);
553 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2u), 0u);
554 ASSERT_EQ(callStack.ExpandCallStack(0, stack3, 2u), 1u);
555 EXPECT_THAT(stack1, testing::ContainerEq(stack3));
556 ASSERT_EQ(callStack.ExpandCallStack(0, stack4, 2u), 0u);
557 }
558
559 /**
560 * @tc.name: ExpandCallStack
561 * @tc.desc:
562 * @tc.type: FUNC
563 */
564 HWTEST_F(CallStackTest, ExpendCallStackABABAB, TestSize.Level1)
565 {
566 /*
567 Caller Called
568 cache A -> B -> C -> A -> B -> C -> A -> B
569 stack2 C
570 expand A -> B -> C -> A -> B -> C
571
572 stack3 B -> C
573 expand A -> B -> C -> A -> B -> C
574
575 stack4 C -> D
576 expand A -> B -> C -> A -> B -> C -> D
577 */
578 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
579 CallStack callStack;
580
581 std::vector<DfxFrame> stack1 = {
582 {0xb, 0xb}, {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb},
583 {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, {0xa, 0xa},
584 };
585 std::vector<DfxFrame> stack2 = {
586 {0xc, 0xc},
587 };
588 std::vector<DfxFrame> stack3 = {
589 {0xc, 0xc},
590 {0xb, 0xb},
591 };
592 std::vector<DfxFrame> stack4 = {
593 {0xd, 0xd},
594 {0xc, 0xc},
595 };
596
597 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
598 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 5u);
599 ASSERT_EQ(callStack.ExpandCallStack(0, stack3), 4u);
600 ASSERT_EQ(callStack.ExpandCallStack(0, stack4), 5u);
601 }
602
603 /**
604 * @tc.name: UnwindCallStack
605 * @tc.desc:
606 * @tc.type: FUNC
607 */
608 HWTEST_F(CallStackTest, UnwindCallStack, TestSize.Level1)
609 {
610 #if is_linux
611 return;
612 #endif
613
614 std::vector<u64> regs;
615 std::vector<u8> data;
616 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_REGS_0, regs);
617 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_DATA_0, data);
618 if (regs.size() > 0 and data.size() > 0) {
619 #ifdef __arm__
620 ASSERT_EQ(regs.size(), 16u);
621 #endif
622 std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles;
623 auto &symbolsFile = symbolsFiles.emplace_back(SymbolsFile::CreateSymbolsFile(
624 SYMBOL_ELF_FILE, TEST_DWARF_ELF));
625 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DWARF_DATA), true);
626 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
627 // fix the name
628 symbolsFile->filePath_ = TEST_DWARF_MMAP.front().fileName;
629
630 VirtualThread thread(getpid(), symbolsFiles);
631 MakeMaps(thread);
632 std::vector<DfxFrame> callFrames;
633 CallStack callStack;
634
635 bool ret = callStack.UnwindCallStack(thread, false, regs.data(), regs.size(), data.data(), data.size(),
636 callFrames);
637 ASSERT_TRUE(ret);
638 ASSERT_LE(TEST_DWARF_FRAMES.size(), callFrames.size());
639 }
640 }
641
642 /**
643 * @tc.name: ClearCache
644 * @tc.desc:
645 * @tc.type: FUNC
646 */
647 HWTEST_F(CallStackTest, ClearCache, TestSize.Level1)
648 {
649 uint n = 0;
650 CallStack callStack;
651 callStack.lastPid_ = n++;
652 callStack.lastAddr_ = n++;
653 callStack.lastData_ = n++;
654 callStack.stackPoint_ = n++;
655 callStack.stackEnd_ = n++;
656 callStack.regsNum_ = n++;
657 callStack.stackSize_ = n++;
658 callStack.ClearCache();
659 EXPECT_EQ(callStack.lastPid_, -1);
660 EXPECT_EQ(callStack.lastAddr_, 0);
661 EXPECT_EQ(callStack.lastData_, 0);
662 EXPECT_EQ(callStack.stackPoint_, 0);
663 EXPECT_EQ(callStack.stackEnd_, 0);
664 EXPECT_EQ(callStack.regs_, nullptr);
665 EXPECT_EQ(callStack.regsNum_, 0);
666 EXPECT_EQ(callStack.stack_, nullptr);
667 EXPECT_EQ(callStack.stackSize_, 0);
668 EXPECT_EQ(callStack.cachedCallFramesMap_.size(), 0);
669 }
670 } // namespace HiPerf
671 } // namespace Developtools
672 } // namespace OHOS
673