1/*
2 * Copyright (c) 2022-2023 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 <gtest/gtest.h>
17#include <cerrno>
18#include <unistd.h>
19
20#include "dfx_fault_stack.h"
21#include "dfx_frame_formatter.h"
22#include "dfx_maps.h"
23#include "dfx_regs.h"
24#include "dfx_ring_buffer_wrapper.h"
25#include "dfx_thread.h"
26#include "dfx_unwind_remote.h"
27
28using namespace OHOS::HiviewDFX;
29using namespace testing::ext;
30using namespace std;
31
32namespace OHOS {
33namespace HiviewDFX {
34class FaultStackUnittest : public testing::Test {
35public:
36    static void SetUpTestCase(void);
37    static void TearDownTestCase(void);
38    void SetUp();
39    void TearDown();
40
41    static int WriteLogFunc(int32_t fd, const char *buf, int len);
42    static std::string result;
43};
44} // namespace HiviewDFX
45} // namespace OHOS
46
47std::string FaultStackUnittest::result = "";
48
49void FaultStackUnittest::SetUpTestCase(void)
50{
51    result = "";
52}
53
54void FaultStackUnittest::TearDownTestCase(void)
55{
56}
57
58void FaultStackUnittest::SetUp(void)
59{
60    DfxRingBufferWrapper::GetInstance().SetWriteFunc(FaultStackUnittest::WriteLogFunc);
61}
62
63void FaultStackUnittest::TearDown(void)
64{
65}
66
67int FaultStackUnittest::WriteLogFunc(int32_t fd, const char *buf, int len)
68{
69    printf("%d: %s", fd, buf);
70    FaultStackUnittest::result.append(std::string(buf, len));
71    return 0;
72}
73
74namespace {
75/**
76 * @tc.name: FaultStackUnittest001
77 * @tc.desc: check whether fault stack and register can be print out
78 * @tc.type: FUNC
79 */
80HWTEST_F(FaultStackUnittest, FaultStackUnittest001, TestSize.Level2)
81{
82    GTEST_LOG_(INFO) << "FaultStackUnittest001: start.";
83
84    auto unwinder = std::make_shared<Unwinder>();
85    bool unwRet = unwinder->UnwindLocal();
86    if (!unwRet) {
87        FAIL() << "Failed to unwind local";
88    }
89    auto frames = unwinder->GetFrames();
90    int childPid = fork();
91    bool isSuccess = childPid >= 0;
92    if (!isSuccess) {
93        ASSERT_FALSE(isSuccess);
94        printf("Failed to fork child process, errno(%d).\n", errno);
95        return;
96    }
97    if (childPid == 0) {
98        uint32_t left = 10;
99        while (left > 0) {
100            left = sleep(left);
101        }
102        _exit(0);
103    }
104    DfxThread thread(childPid, childPid, childPid);
105    ASSERT_EQ(true, thread.Attach());
106    auto maps = DfxMaps::Create(childPid);
107    auto reg = DfxRegs::CreateRemoteRegs(childPid);
108    std::unique_ptr<FaultStack> stack = std::make_unique<FaultStack>(childPid);
109    stack->CollectStackInfo(frames);
110    stack->CollectRegistersBlock(reg, maps);
111    stack->Print();
112    thread.Detach();
113
114    if (result.find("Memory near registers") == std::string::npos) {
115        FAIL();
116    }
117
118    if (result.find("FaultStack") == std::string::npos) {
119        FAIL();
120    }
121
122    if (result.find("pc") == std::string::npos) {
123        FAIL();
124    }
125
126    if (result.find("sp2:") == std::string::npos) {
127        FAIL();
128    }
129    GTEST_LOG_(INFO) << "Result Log length:" << result.length();
130    ASSERT_GT(result.length(), 0);
131    GTEST_LOG_(INFO) << "FaultStackUnittest001: end.";
132}
133}