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
28 using namespace OHOS::HiviewDFX;
29 using namespace testing::ext;
30 using namespace std;
31
32 namespace OHOS {
33 namespace HiviewDFX {
34 class FaultStackUnittest : public testing::Test {
35 public:
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
47 std::string FaultStackUnittest::result = "";
48
SetUpTestCase(void)49 void FaultStackUnittest::SetUpTestCase(void)
50 {
51 result = "";
52 }
53
TearDownTestCase(void)54 void FaultStackUnittest::TearDownTestCase(void)
55 {
56 }
57
SetUp(void)58 void FaultStackUnittest::SetUp(void)
59 {
60 DfxRingBufferWrapper::GetInstance().SetWriteFunc(FaultStackUnittest::WriteLogFunc);
61 }
62
TearDown(void)63 void FaultStackUnittest::TearDown(void)
64 {
65 }
66
WriteLogFunc(int32_t fd, const char *buf, int len)67 int 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
74 namespace {
75 /**
76 * @tc.name: FaultStackUnittest001
77 * @tc.desc: check whether fault stack and register can be print out
78 * @tc.type: FUNC
79 */
HWTEST_F(FaultStackUnittest, FaultStackUnittest001, TestSize.Level2)80 HWTEST_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 }