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
18using namespace testing::ext;
19using namespace testing;
20using namespace std;
21using namespace OHOS::HiviewDFX;
22namespace OHOS {
23namespace Developtools {
24namespace HiPerf {
25class CallStackTest : public testing::Test {
26public:
27    static void SetUpTestCase(void);
28    static void TearDownTestCase(void);
29    void SetUp();
30    void TearDown();
31    default_random_engine rnd_;
32};
33
34void CallStackTest::SetUpTestCase()
35{
36    DebugLogger::GetInstance()->Reset();
37    DebugLogger::GetInstance()->OpenLog(DEFAULT_UT_LOG_DIR + "CallStackTest.txt");
38}
39
40void CallStackTest::TearDownTestCase()
41{
42    DebugLogger::GetInstance()->RestoreLog();
43}
44
45void CallStackTest::SetUp() {}
46
47void CallStackTest::TearDown() {}
48
49/**
50 * @tc.name: ExpandCallStack
51 * @tc.desc:
52 * @tc.type: FUNC
53 */
54HWTEST_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 */
82HWTEST_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 */
112HWTEST_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 */
143HWTEST_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 */
175HWTEST_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 */
206HWTEST_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 */
236HWTEST_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 */
270HWTEST_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 */
304HWTEST_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 */
338HWTEST_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 */
369HWTEST_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 */
418HWTEST_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 */
449HWTEST_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 */
485HWTEST_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 */
504HWTEST_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 */
521HWTEST_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 */
567HWTEST_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 */
611HWTEST_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