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<DfxFrame> stack1 = {
66 {0x1u, 0x1u},
67 {0x2u, 0x2u},
68 {0x3u, 0x3u},
69 };
70 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
94 {0x1u, 0x1u},
95 {0x2u, 0x2u},
96 {0x3u, 0x3u},
97 };
98 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
124 {0x1u, 0x1u},
125 {0x2u, 0x2u},
126 {0x3u, 0x3u},
127 };
128 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
155 {0x1u, 0x1u},
156 {0x2u, 0x2u},
157 {0x3u, 0x3u},
158 };
159 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
187 {0x1u, 0x1u},
188 {0x2u, 0x2u},
189 {0x3u, 0x3u},
190 };
191 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
218 {0x1u, 0x1u},
219 {0x2u, 0x2u},
220 {0x3u, 0x3u},
221 };
222 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
248 {0x1u, 0x1u},
249 {0x2u, 0x2u},
250 {0x3u, 0x3u},
251 };
252 std::vector<DfxFrame> stack2 = {
253 {0x2u, 0x2u},
254 };
255 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
282 {0x1u, 0x1u},
283 {0x2u, 0x2u},
284 {0x3u, 0x3u},
285 };
286 std::vector<DfxFrame> stack2 = {
287 {0x2u, 0x2u},
288 };
289 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
316 {0x1u, 0x1u},
317 {0x2u, 0x2u},
318 {0x3u, 0x3u},
319 };
320 std::vector<DfxFrame> stack2 = {
321 {0x2u, 0x2u},
322 };
323 std::vector<DfxFrame> 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<DfxFrame> stack1 = {
350 {0x1u, 0x1u},
351 {0x2u, 0x2u},
352 {0x3u, 0x3u},
353 };
354 std::vector<DfxFrame> 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<DfxFrame> stackFull = {
382 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA},
383 };
384 std::vector<DfxFrame> stackBC = {
385 {0xC, 0xC},
386 {0xB, 0xB},
387 };
388 std::vector<DfxFrame> stackABC = {
389 {0xC, 0xC},
390 {0xB, 0xB},
391 {0xA, 0xA},
392 };
393 std::vector<DfxFrame> stackBFF = {
394 {0xF, 0xF},
395 {0xF, 0xF},
396 {0xB, 0xB},
397 };
398 std::vector<DfxFrame> 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<DfxFrame> stackFull = {
431 {0xC, 0xC},
432 {0xB, 0xB},
433 {0xA, 0xA},
434 };
435 std::vector<DfxFrame> 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<DfxFrame> stack0 = {
460 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA},
461 };
462 std::vector<DfxFrame> stack1 = {
463 {0xE, 0xE},
464 {0xD, 0xD},
465 {0xC, 0xC},
466 {0x2, 0x2},
467 };
468 std::vector<DfxFrame> stackC = {
469 {0xC, 0xC},
470 };
471 std::vector<DfxFrame> 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<DfxFrame> 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<DfxFrame> 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: ExpandCallStack
501 * @tc.desc:
502 * @tc.type: FUNC
503 */
504 HWTEST_F(CallStackTest, ExpendCallStackSmall, TestSize.Level1)
505 {
506 CallStack callStack;
507 std::vector<DfxFrame> stack0 = {};
508 std::vector<DfxFrame> stack1 = {{0x1, 0x1}};
509 std::vector<DfxFrame> stack2 = {{0x1, 0x1}, {0x2, 0x2}};
510 ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u);
511 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
512 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
513 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u);
514 }
515
516 /**
517 * @tc.name: ExpandCallStack
518 * @tc.desc:
519 * @tc.type: FUNC
520 */
521 HWTEST_F(CallStackTest, ExpendCallStackLimit, TestSize.Level1)
522 {
523 /*
524 3 2 1 0
525 cache A -> B -> C
526 stack2 C
527 expand C
528
529 stack3 B -> C
530 expand A -> B -> C
531
532 stack4 C -> D
533 expand C
534 */
535 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
536 CallStack callStack;
537
538 std::vector<DfxFrame> stack1 = {
539 {0x1u, 0x1u},
540 {0x2u, 0x2u},
541 {0x3u, 0x3u},
542 };
543 std::vector<DfxFrame> stack2 = {
544 {0x1u, 0x1u},
545 };
546 std::vector<DfxFrame> stack3 = {
547 {0x1u, 0x1u},
548 {0x2u, 0x2u},
549 };
550 std::vector<DfxFrame> stack4 = {
551 {0x0u, 0x0u},
552 {0x1u, 0x1u},
553 };
554
555 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2u), 0u);
556 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2u), 0u);
557 ASSERT_EQ(callStack.ExpandCallStack(0, stack3, 2u), 1u);
558 EXPECT_THAT(stack1, ContainerEq(stack3));
559 ASSERT_EQ(callStack.ExpandCallStack(0, stack4, 2u), 0u);
560 }
561
562 /**
563 * @tc.name: ExpandCallStack
564 * @tc.desc:
565 * @tc.type: FUNC
566 */
567 HWTEST_F(CallStackTest, ExpendCallStackABABAB, TestSize.Level1)
568 {
569 /*
570 Caller Called
571 cache A -> B -> C -> A -> B -> C -> A -> B
572 stack2 C
573 expand A -> B -> C -> A -> B -> C
574
575 stack3 B -> C
576 expand A -> B -> C -> A -> B -> C
577
578 stack4 C -> D
579 expand A -> B -> C -> A -> B -> C -> D
580 */
581 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
582 CallStack callStack;
583
584 std::vector<DfxFrame> stack1 = {
585 {0xb, 0xb}, {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb},
586 {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, {0xa, 0xa},
587 };
588 std::vector<DfxFrame> stack2 = {
589 {0xc, 0xc},
590 };
591 std::vector<DfxFrame> stack3 = {
592 {0xc, 0xc},
593 {0xb, 0xb},
594 };
595 std::vector<DfxFrame> stack4 = {
596 {0xd, 0xd},
597 {0xc, 0xc},
598 };
599
600 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u);
601 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 5u);
602 ASSERT_EQ(callStack.ExpandCallStack(0, stack3), 4u);
603 ASSERT_EQ(callStack.ExpandCallStack(0, stack4), 5u);
604 }
605
606 /**
607 * @tc.name: UnwindCallStack
608 * @tc.desc:
609 * @tc.type: FUNC
610 */
611 HWTEST_F(CallStackTest, UnwindCallStack, TestSize.Level1)
612 {
613 #if is_linux
614 return;
615 #endif
616
617 std::vector<u64> regs;
618 std::vector<u8> data;
619 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_REGS_0, regs);
620 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_DATA_0, data);
621 if (regs.size() > 0 and data.size() > 0) {
622 #ifdef __arm__
623 ASSERT_EQ(regs.size(), 16u);
624 #endif
625 std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles;
626 auto &symbolsFile = symbolsFiles.emplace_back(SymbolsFile::CreateSymbolsFile(
627 SYMBOL_ELF_FILE, TEST_DWARF_ELF));
628 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DWARF_DATA), true);
629 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
630 // fix the name
631 symbolsFile->filePath_ = TEST_DWARF_MMAP.front().fileName;
632
633 VirtualThread thread(getpid(), symbolsFiles);
634 MakeMaps(thread);
635 std::vector<DfxFrame> callFrames;
636 CallStack callStack;
637
638 bool ret = callStack.UnwindCallStack(thread, false, regs.data(), regs.size(), data.data(), data.size(),
639 callFrames);
640 ASSERT_TRUE(ret);
641 ASSERT_LE(TEST_DWARF_FRAMES.size(), callFrames.size());
642 }
643 }
644 } // namespace HiPerf
645 } // namespace Developtools
646 } // namespace OHOS
647