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