1 /*
2  * Copyright (c) 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 <map>
18 #include <memory>
19 #include <securec.h>
20 #include <csignal>
21 #include <string>
22 
23 #include "dfx_signal.h"
24 
25 using namespace OHOS::HiviewDFX;
26 using namespace testing::ext;
27 using namespace std;
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 class DfxSignalTest : public testing::Test {
32 public:
SetUpTestCase(void)33     static void SetUpTestCase(void) {}
TearDownTestCase(void)34     static void TearDownTestCase(void) {}
SetUp()35     void SetUp() {}
TearDown()36     void TearDown() {}
37 };
38 } // namespace HiviewDFX
39 } // namespace OHOS
40 
41 namespace {
42 /**
43  * @tc.name: DfxSignalTest001
44  * @tc.desc: test DfxSignal functions
45  * @tc.type: FUNC
46  */
47 HWTEST_F(DfxSignalTest, DfxSignalTest001, TestSize.Level2)
48 {
49     GTEST_LOG_(INFO) << "DfxSignalTest001: start.";
50     siginfo_t si = {
51         .si_signo = SIGSEGV,
52         .si_errno = 0,
53         .si_code = -1,
54         .si_value.sival_int = static_cast<int>(gettid())
55     };
56     std::map<int, std::string> sigKey = {
57         { SIGILL, string("SIGILL") },
58         { SIGTRAP, string("SIGTRAP") },
59         { SIGABRT, string("SIGABRT") },
60         { SIGBUS, string("SIGBUS") },
61         { SIGFPE, string("SIGFPE") },
62         { SIGSEGV, string("SIGSEGV") },
63         { SIGSTKFLT, string("SIGSTKFLT") },
64         { SIGSYS, string("SIGSYS") },
65     };
66     for (auto sigKey : sigKey) {
67         std::string sigKeyword = "Signal:";
68         si.si_signo = sigKey.first;
69         sigKeyword += sigKey.second;
70         std::string sigStr = DfxSignal::PrintSignal(si) + "\n";
71         GTEST_LOG_(INFO) << sigStr;
72         ASSERT_TRUE(sigStr.find(sigKeyword) != std::string::npos);
73     }
74     GTEST_LOG_(INFO) << "DfxSignalTest001: end.";
75 }
76 
77 /**
78  * @tc.name: DfxSignalTest002
79  * @tc.desc: test if signal info is available
80  * @tc.type: FUNC
81  */
82 HWTEST_F(DfxSignalTest, DfxSignalTest002, TestSize.Level2)
83 {
84     GTEST_LOG_(INFO) << "DfxSignalTest002: start.";
85     int32_t input = 1;
86     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
87     bool ret = signal->IsAvailable();
88     EXPECT_EQ(true, ret != true) << "DfxSignalTest002 Failed";
89     GTEST_LOG_(INFO) << "DfxSignalTest002: end.";
90 }
91 
TestSignalHandler(int sig,siginfo_t * si,void * context)92 static void TestSignalHandler(int sig, siginfo_t * si, void * context)
93 {
94     GTEST_LOG_(INFO) << "Enter TestSignalHandler";
95 }
96 
97 /**
98  * @tc.name: DfxSignalTest003
99  * @tc.desc: test if signal info is available in normal status
100  * @tc.type: FUNC
101  */
102 HWTEST_F(DfxSignalTest, DfxSignalTest003, TestSize.Level2)
103 {
104     GTEST_LOG_(INFO) << "DfxSignalTest003: start.";
105     pid_t child = fork();
106     if (child == 0) {
107         int32_t input = SIGINT;
108         struct sigaction action;
109         (void)memset_s(&action, sizeof(action), 0, sizeof(action));
110         action.sa_sigaction = TestSignalHandler;
111         action.sa_flags = SA_SIGINFO;
112         int rc = sigaction(input, &action, nullptr);
113         ASSERT_EQ(rc, 0) << "DfxSignalTest003 Failed, sigaction signal failed";
114 
115         std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
116         bool ret = signal->IsAvailable();
117         ASSERT_EQ(true, ret) << "DfxSignalTest003 Failed";
118         _exit(0);
119     }
120     int status;
121     int ret = wait(&status);
122     ASSERT_EQ(status, 0);
123     GTEST_LOG_(INFO) << "Status:" << status << " Result:" << ret;
124     GTEST_LOG_(INFO) << "DfxSignalTest003: end.";
125 }
126 
127 /**
128  * @tc.name: DfxSignalTest004
129  * @tc.desc: test if addr is available
130  * @tc.type: FUNC
131  */
132 HWTEST_F(DfxSignalTest, DfxSignalTest004, TestSize.Level2)
133 {
134     GTEST_LOG_(INFO) << "DfxSignalTest004: start.";
135     int32_t input = -100; // -100 is an unexpected signal
136     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
137     bool ret = signal->IsAddrAvailable();
138     EXPECT_EQ(true, ret != true) << "DfxSignalTest004 Failed";
139     GTEST_LOG_(INFO) << "DfxSignalTest004: end.";
140 }
141 
142 /**
143  * @tc.name: DfxSignalTest005
144  * @tc.desc: test if addr is available in normal status
145  * @tc.type: FUNC
146  */
147 HWTEST_F(DfxSignalTest, DfxSignalTest005, TestSize.Level2)
148 {
149     GTEST_LOG_(INFO) << "DfxSignalTest005: start.";
150     int32_t input = SIGSEGV;
151     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
152     bool ret = signal->IsAddrAvailable();
153     EXPECT_EQ(true, ret) << "DfxSignalTest005 Failed";
154     GTEST_LOG_(INFO) << "DfxSignalTest005: end.";
155 }
156 
157 /**
158  * @tc.name: DfxSignalTest006
159  * @tc.desc: test if pid is available
160  * @tc.type: FUNC
161  */
162 HWTEST_F(DfxSignalTest, DfxSignalTest006, TestSize.Level2)
163 {
164     int32_t input = 100; // 100 is an unexpected signal
165     GTEST_LOG_(INFO) << "DfxSignalTest006: start.";
166     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
167     bool ret = signal->IsPidAvailable();
168     EXPECT_EQ(true, ret != true) << "DfxSignalTest006 Failed";
169     GTEST_LOG_(INFO) << "DfxSignalTest006: end.";
170 }
171 
172 /**
173  * @tc.name: DfxSignalTest007
174  * @tc.desc: test if pid is available in normal status
175  * @tc.type: FUNC
176  */
177 HWTEST_F(DfxSignalTest, DfxSignalTest007, TestSize.Level2)
178 {
179     int32_t input = SI_USER;
180     GTEST_LOG_(INFO) << "DfxSignalTest007: start.";
181     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
182     bool ret = signal->IsPidAvailable();
183     EXPECT_EQ(true, ret) << "DfxSignalTest007 Failed";
184     GTEST_LOG_(INFO) << "DfxSignalTest007: end.";
185 }
186 
187 /**
188  * @tc.name: DfxSignalTest008
189  * @tc.desc: test if GetSignal
190  * @tc.type: FUNC
191  */
192 HWTEST_F(DfxSignalTest, DfxSignalTest008, TestSize.Level2)
193 {
194     GTEST_LOG_(INFO) << "DfxSignalTest008: start.";
195     int32_t input = 1;
196     std::shared_ptr<DfxSignal> signal = std::make_shared<DfxSignal>(input);
197     int32_t output = signal->GetSignal();
198     EXPECT_EQ(true, output == input) << "DfxSignalTest008 Failed";
199     GTEST_LOG_(INFO) << "DfxSignalTest008: end.";
200 }
201 
202 std::map<int32_t, std::string> sigKeys = {
203     { SIGILL, std::string("SIGILL") },
204     { SIGTRAP, std::string("SIGTRAP") },
205     { SIGBUS, std::string("SIGBUS") },
206     { SIGFPE, std::string("SIGFPE") },
207     { SIGSEGV, std::string("SIGSEGV") },
208 };
209 std::map<int, std::string> segvCode = {
210     { SEGV_MAPERR, string("SEGV_MAPERR") },
211     { SEGV_ACCERR, string("SEGV_ACCERR") },
212     { SI_USER, string("SI_USER") },
213 };
214 std::map<int, std::string> trapCode = {
215     { TRAP_BRKPT, string("TRAP_BRKPT") },
216     { TRAP_TRACE, string("TRAP_TRACE") },
217     { TRAP_BRANCH, string("TRAP_BRANCH") },
218     { TRAP_HWBKPT, string("TRAP_HWBKPT") },
219     { SI_USER, string("SI_USER") },
220 };
221 std::map<int, std::string> illCode = {
222     { ILL_ILLOPC, string("ILL_ILLOPC") },
223     { ILL_ILLOPN, string("ILL_ILLOPN") },
224     { ILL_ILLADR, string("ILL_ILLADR") },
225     { ILL_ILLTRP, string("ILL_ILLTRP") },
226     { ILL_PRVOPC, string("ILL_PRVOPC") },
227     { ILL_PRVREG, string("ILL_PRVREG") },
228     { ILL_COPROC, string("ILL_COPROC") },
229     { ILL_BADSTK, string("ILL_BADSTK") },
230     { SI_USER, string("SI_USER") },
231 };
232 std::map<int, std::string> fpeCode = {
233     { FPE_INTDIV, string("FPE_INTDIV") },
234     { FPE_INTOVF, string("FPE_INTOVF") },
235     { FPE_FLTDIV, string("FPE_FLTDIV") },
236     { FPE_FLTOVF, string("FPE_FLTOVF") },
237     { FPE_FLTUND, string("FPE_FLTUND") },
238     { FPE_FLTRES, string("FPE_FLTRES") },
239     { FPE_FLTINV, string("FPE_FLTINV") },
240     { FPE_FLTSUB, string("FPE_FLTSUB") },
241     { SI_USER, string("SI_USER") },
242 };
243 std::map<int, std::string> busCode = {
244     { BUS_ADRALN, string("BUS_ADRALN") },
245     { BUS_ADRERR, string("BUS_ADRERR") },
246     { BUS_OBJERR, string("BUS_OBJERR") },
247     { BUS_MCEERR_AR, string("BUS_MCEERR_AR") },
248     { BUS_MCEERR_AO, string("BUS_MCEERR_AO") },
249     { SI_USER, string("SI_USER") },
250 };
251 /**
252  * @tc.name: DfxSignalTest009
253  * @tc.desc: test DfxSignal functions
254  * @tc.type: FUNC
255  */
256 HWTEST_F(DfxSignalTest, DfxSignalTest009, TestSize.Level2)
257 {
258     GTEST_LOG_(INFO) << "DfxSignalTest009: start.";
259     siginfo_t si = {
260         .si_signo = SIGSEGV,
261         .si_errno = 0,
262         .si_code = -1,
263         .si_value.sival_int = static_cast<int>(gettid())
264     };
265     for (auto sigKey : sigKeys) {
266         si.si_signo = sigKey.first;
267         std::map<int, std::string> codeMap;
268         switch (si.si_signo) {
269             case SIGILL:
270                 codeMap = illCode;
271                 break;
272             case SIGTRAP:
273                 codeMap = trapCode;
274                 break;
275             case SIGBUS:
276                 codeMap = busCode;
277                 break;
278             case SIGFPE:
279                 codeMap = fpeCode;
280                 break;
281             case SIGSEGV:
282                 codeMap = segvCode;
283                 break;
284             default:
285                 break;
286         }
287         for (auto& code : codeMap) {
288             std::string sigKeyword = "Signal:";
289             sigKeyword += sigKey.second;
290             si.si_code = code.first;
291             sigKeyword = sigKeyword + "(" + code.second + ")";
292             std::string sigStr = DfxSignal::PrintSignal(si) + "\n";
293             GTEST_LOG_(INFO) << sigStr;
294             ASSERT_TRUE(sigStr.find(sigKeyword) != std::string::npos);
295         }
296     }
297     GTEST_LOG_(INFO) << "DfxSignalTest009: end.";
298 }
299 }
300