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 && t.at(i).size() < REGISTERS_LENGTH) {
120 count--;
121 }
122 count++;
123 j++;
124 if (j == length) {
125 break;
126 }
127 continue;
128 }
129 i++;
130 }
131 file.close();
132 GTEST_LOG_(INFO) << count << " keys matched.";
133 return count;
134 }
135
CheckLocalCrashKeyWords(const string & filePath,pid_t pid,int sig)136 static bool CheckLocalCrashKeyWords(const string& filePath, pid_t pid, int sig)
137 {
138 if (filePath.empty() || pid <= 0) {
139 return false;
140 }
141 map<int, string> sigKey = {
142 { SIGILL, string("Signal(4)") },
143 { SIGABRT, string("Signal(6)") },
144 { SIGBUS, string("Signal(7)") },
145 { SIGSEGV, string("Signal(11)") },
146 };
147 string sigKeyword = "";
148 map<int, string>::iterator iter = sigKey.find(sig);
149 if (iter != sigKey.end()) {
150 sigKeyword = iter->second;
151 }
152 string keywords[] = {
153 "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword, "Tid:", "#00", "test_signalhandler"
154 };
155 int length = sizeof(keywords) / sizeof(keywords[0]);
156 return CheckKeyWords(filePath, keywords, length) == length;
157 }
158
159 /**
160 * @tc.name: LocalHandlerTest001
161 * @tc.desc: test crashlocalhandler signo(SIGILL)
162 * @tc.type: FUNC
163 */
164 HWTEST_F(SignalHandlerTest, LocalHandlerTest001, TestSize.Level2)
165 {
166 GTEST_LOG_(INFO) << "DfxProcessDumpTest020: start.";
167 pid_t pid = fork();
168 if (pid < 0) {
169 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
170 } else if (pid == 0) {
171 DFX_InstallLocalSignalHandler();
172 sleep(1);
173 } else {
174 usleep(10000); // 10000 : sleep 10ms
175 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
176 kill(pid, SIGILL);
177 sleep(2); // 2 : wait for cppcrash generating
178 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
179 ASSERT_TRUE(ret);
180 }
181 GTEST_LOG_(INFO) << "DfxProcessDumpTest020: end.";
182 }
183
184 /**
185 * @tc.name: LocalHandlerTest002
186 * @tc.desc: test crashlocalhandler signo(SIGABRT)
187 * @tc.type: FUNC
188 */
189 HWTEST_F(SignalHandlerTest, LocalHandlerTest002, TestSize.Level2)
190 {
191 GTEST_LOG_(INFO) << "LocalHandlerTest002: start.";
192 pid_t pid = fork();
193 if (pid < 0) {
194 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
195 } else if (pid == 0) {
196 DFX_InstallLocalSignalHandler();
197 sleep(1);
198 } else {
199 usleep(10000); // 10000 : sleep 10ms
200 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
201 kill(pid, SIGABRT);
202 sleep(2); // 2 : wait for cppcrash generating
203 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGABRT);
204 ASSERT_TRUE(ret);
205 }
206 GTEST_LOG_(INFO) << "LocalHandlerTest002: end.";
207 }
208
209 /**
210 * @tc.name: LocalHandlerTest003
211 * @tc.desc: test crashlocalhandler signo(SIGBUS)
212 * @tc.type: FUNC
213 */
214 HWTEST_F(SignalHandlerTest, LocalHandlerTest003, TestSize.Level2)
215 {
216 GTEST_LOG_(INFO) << "LocalHandlerTest003: start.";
217 pid_t pid = fork();
218 if (pid < 0) {
219 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
220 } else if (pid == 0) {
221 DFX_InstallLocalSignalHandler();
222 sleep(1);
223 } else {
224 usleep(10000); // 10000 : sleep 10ms
225 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
226 kill(pid, SIGBUS);
227 sleep(2); // 2 : wait for cppcrash generating
228 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
229 ASSERT_TRUE(ret);
230 }
231 GTEST_LOG_(INFO) << "LocalHandlerTest003: end.";
232 }
233
234 /**
235 * @tc.name: LocalHandlerTest004
236 * @tc.desc: test crashlocalhandler signo(SIGSEGV)
237 * @tc.type: FUNC
238 */
239 HWTEST_F(SignalHandlerTest, LocalHandlerTest004, TestSize.Level2)
240 {
241 GTEST_LOG_(INFO) << "LocalHandlerTest004: start.";
242 pid_t pid = fork();
243 if (pid < 0) {
244 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
245 } else if (pid == 0) {
246 DFX_InstallLocalSignalHandler();
247 sleep(1);
248 } else {
249 usleep(10000); // 10000 : sleep 10ms
250 GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
251 kill(pid, SIGSEGV);
252 sleep(2); // 2 : wait for cppcrash generating
253 bool ret = CheckLocalCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
254 ASSERT_TRUE(ret);
255 }
256 GTEST_LOG_(INFO) << "LocalHandlerTest004: end.";
257 }
258 } // namespace HiviewDFX
259 } // namepsace OHOS
260