1 /*
2 * Copyright (c) 2022 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
18 #include <fstream>
19 #include <map>
20 #include <csignal>
21 #include <string>
22 #include <unistd.h>
23 #include <vector>
24
25 #include "dfx_define.h"
26 #include "dfx_signal_local_handler.h"
27 #include "directory_ex.h"
28
29 #if defined(__arm__)
30 #define REGISTERS "r0:","r1:","r2:","r3:","r4:","r5:","r6:",\
31 "r7:","r8:","r9:","r10:","fp:","ip:","sp:","lr:","pc:"
32 #define REGISTERS_NUM 16
33 #define REGISTERS_LENGTH 10
34 #elif defined(__aarch64__)
35 #define REGISTERS "x0:","x1:","x2:","x3:","x4:","x5:","x6:","x7:","x8:",\
36 "x9:","x10:","x11:","x12:","x13:","x14:","x15:","x16:",\
37 "x17:","x18:","x19:","x20:","x21:","x22:","x23:","x24:",\
38 "x25:","x26:","x27:","x28:","x29:","lr:","sp:","pc:"
39 #define REGISTERS_NUM 33
40 #define REGISTERS_LENGTH 18
41 #endif
42
43 using namespace testing;
44 using namespace testing::ext;
45 using namespace std;
46
47 namespace OHOS {
48 namespace HiviewDFX {
49 class SignalHandlerTest : public testing::Test {
50 public:
51 static void SetUpTestCase();
52 static void TearDownTestCase();
53 void SetUp();
54 void TearDown();
55 };
56
SetUpTestCase()57 void SignalHandlerTest::SetUpTestCase()
58 {}
59
TearDownTestCase()60 void SignalHandlerTest::TearDownTestCase()
61 {}
62
SetUp()63 void SignalHandlerTest::SetUp()
64 {}
65
TearDown()66 void SignalHandlerTest::TearDown()
67 {}
68
CountLines(const string & filename)69 static int CountLines(const string& filename)
70 {
71 ifstream readStream;
72 string tempData;
73 readStream.open(filename.c_str(), ios::in);
74 if (readStream.fail()) {
75 return 0;
76 } else {
77 int n = 0;
78 while (getline(readStream, tempData, '\n')) {
79 n++;
80 }
81 readStream.close();
82 return n;
83 }
84 }
85
GetCppCrashFileName(pid_t pid)86 static string GetCppCrashFileName(pid_t pid)
87 {
88 if (pid <= 0) {
89 return "";
90 }
91 vector<string> files;
92 OHOS::GetDirFiles("/data/log/faultlog/temp", files);
93 string fileNamePrefix = "cppcrash-" + to_string(pid);
94 for (const auto& file : files) {
95 if (file.find(fileNamePrefix) != string::npos) {
96 return file;
97 }
98 }
99 return "";
100 }
101
CheckKeyWords(const string & filePath,string * keywords,int length)102 static int CheckKeyWords(const string& filePath, string *keywords, int length)
103 {
104 ifstream file;
105 file.open(filePath.c_str(), ios::in);
106 long lines = CountLines(filePath);
107 vector<string> t(lines * 4); // 4 : max string blocks of one line
108 int i = 0;
109 int j = 0;
110 string::size_type idx;
111 int count = 0;
112 int minRegIdx = 6; // 6 : index of REGISTERS
113 int maxRegIdx = minRegIdx + REGISTERS_NUM + 1;
114 while (!file.eof()) {
115 file >> t.at(i);
116 idx = t.at(i).find(keywords[j]);
117 if (idx != string::npos) {
118 GTEST_LOG_(INFO) << t.at(i);
119 if (j > minRegIdx && j < maxRegIdx) {
120 if (t.at(i).size() < REGISTERS_LENGTH) {
121 count--;
122 }
123 }
124 count++;
125 j++;
126 if (j == length) {
127 break;
128 }
129 continue;
130 }
131 i++;
132 }
133 file.close();
134 GTEST_LOG_(INFO) << count << " keys matched.";
135 return count;
136 }
137
CheckLocalCrashKeyWords(const string & filePath,pid_t pid,int sig)138 static bool CheckLocalCrashKeyWords(const string& filePath, pid_t pid, int sig)
139 {
140 if (filePath.empty() || pid <= 0) {
141 return false;
142 }
143 map<int, string> sigKey = {
144 { SIGILL, string("Signal(4)") },
145 { SIGABRT, string("Signal(6)") },
146 { SIGBUS, string("Signal(7)") },
147 { SIGSEGV, string("Signal(11)") },
148 };
149 string sigKeyword = "";
150 map<int, string>::iterator iter = sigKey.find(sig);
151 if (iter != sigKey.end()) {
152 sigKeyword = iter->second;
153 }
154 string keywords[] = {
155 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword, "Tid:", "#00", "test_signalhandler"
156 };
157 int length = sizeof(keywords) / sizeof(keywords[0]);
158 return CheckKeyWords(filePath, keywords, length) == length;
159 }
160
161 /**
162 * @tc.name: LocalHandlerTest001
163 * @tc.desc: test crashlocalhandler signo(SIGILL)
164 * @tc.type: FUNC
165 */
166 HWTEST_F(SignalHandlerTest, LocalHandlerTest001, TestSize.Level2)
167 {
168 GTEST_LOG_(INFO) << "DfxProcessDumpTest020: start.";
169 pid_t pid = fork();
170 if (pid < 0) {
171 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
172 } else if (pid == 0) {
173 DFX_InstallLocalSignalHandler();
174 sleep(1);
175 } else {
176 usleep(10000); // 10000 : sleep 10ms
177 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
178 kill(pid, SIGILL);
179 sleep(2); // 2 : wait for cppcrash generating
180 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
181 ASSERT_TRUE(ret);
182 }
183 GTEST_LOG_(INFO) << "DfxProcessDumpTest020: end.";
184 }
185
186 /**
187 * @tc.name: LocalHandlerTest002
188 * @tc.desc: test crashlocalhandler signo(SIGABRT)
189 * @tc.type: FUNC
190 */
191 HWTEST_F(SignalHandlerTest, LocalHandlerTest002, TestSize.Level2)
192 {
193 GTEST_LOG_(INFO) << "LocalHandlerTest002: start.";
194 pid_t pid = fork();
195 if (pid < 0) {
196 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
197 } else if (pid == 0) {
198 DFX_InstallLocalSignalHandler();
199 sleep(1);
200 } else {
201 usleep(10000); // 10000 : sleep 10ms
202 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
203 kill(pid, SIGABRT);
204 sleep(2); // 2 : wait for cppcrash generating
205 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
206 ASSERT_TRUE(ret);
207 }
208 GTEST_LOG_(INFO) << "LocalHandlerTest002: end.";
209 }
210
211 /**
212 * @tc.name: LocalHandlerTest003
213 * @tc.desc: test crashlocalhandler signo(SIGBUS)
214 * @tc.type: FUNC
215 */
216 HWTEST_F(SignalHandlerTest, LocalHandlerTest003, TestSize.Level2)
217 {
218 GTEST_LOG_(INFO) << "LocalHandlerTest003: start.";
219 pid_t pid = fork();
220 if (pid < 0) {
221 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
222 } else if (pid == 0) {
223 DFX_InstallLocalSignalHandler();
224 sleep(1);
225 } else {
226 usleep(10000); // 10000 : sleep 10ms
227 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
228 kill(pid, SIGBUS);
229 sleep(2); // 2 : wait for cppcrash generating
230 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
231 ASSERT_TRUE(ret);
232 }
233 GTEST_LOG_(INFO) << "LocalHandlerTest003: end.";
234 }
235
236 /**
237 * @tc.name: LocalHandlerTest004
238 * @tc.desc: test crashlocalhandler signo(SIGSEGV)
239 * @tc.type: FUNC
240 */
241 HWTEST_F(SignalHandlerTest, LocalHandlerTest004, TestSize.Level2)
242 {
243 GTEST_LOG_(INFO) << "LocalHandlerTest004: start.";
244 pid_t pid = fork();
245 if (pid < 0) {
246 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
247 } else if (pid == 0) {
248 DFX_InstallLocalSignalHandler();
249 sleep(1);
250 } else {
251 usleep(10000); // 10000 : sleep 10ms
252 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
253 kill(pid, SIGSEGV);
254 sleep(2); // 2 : wait for cppcrash generating
255 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
256 ASSERT_TRUE(ret);
257 }
258 GTEST_LOG_(INFO) << "LocalHandlerTest004: end.";
259 }
260 } // namespace HiviewDFX
261 } // namepsace OHOS
262