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 */
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 if (childPid == 0) {
92 uint32_t left = 10;
93 while (left > 0) {
94 left = sleep(left);
95 }
96 _exit(0);
97 } else if (childPid < 0) {
98 printf("Failed to fork child process, errno(%d).\n", errno);
99 return;
100 }
101
102 DfxThread thread(childPid, childPid, childPid);
103 ASSERT_EQ(true, thread.Attach());
104 auto maps = DfxMaps::Create(childPid);
105 auto reg = DfxRegs::CreateRemoteRegs(childPid);
106 std::unique_ptr<FaultStack> stack = std::make_unique<FaultStack>(childPid);
107 stack->CollectStackInfo(frames);
108 stack->CollectRegistersBlock(reg, maps);
109 stack->Print();
110 thread.Detach();
111
112 if (result.find("Memory near registers") == std::string::npos) {
113 FAIL();
114 }
115
116 if (result.find("FaultStack") == std::string::npos) {
117 FAIL();
118 }
119
120 if (result.find("pc") == std::string::npos) {
121 FAIL();
122 }
123
124 if (result.find("sp2:") == std::string::npos) {
125 FAIL();
126 }
127 GTEST_LOG_(INFO) << "Result Log length:" << result.length();
128 ASSERT_GT(result.length(), 0);
129 GTEST_LOG_(INFO) << "FaultStackUnittest001: end.";
130 }
131 }