• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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