• 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 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