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 <fstream>
18 #include <map>
19 #include <csignal>
20 #include <dlfcn.h>
21 #include <string>
22 #include <unistd.h>
23 #include <vector>
24
25 #include "dfx_config.h"
26 #include "dfx_define.h"
27 #include "dfx_logger.h"
28 #include "dfx_test_util.h"
29 #include "dfx_util.h"
30 #include "directory_ex.h"
31 #include "dfx_socket_request.h"
32 #include "multithread_constructor.h"
33 #include "process_dumper.h"
34 #include "faultlogger_client_msg.h"
35
36 using namespace OHOS::HiviewDFX;
37 using namespace testing::ext;
38 using namespace std;
39
40 using RecordAppExitReason = int (*)(int reason, const char *exitMsg);
41
42 namespace OHOS {
43 namespace HiviewDFX {
44 class DfxProcessDumpTest : public testing::Test {
45 public:
46 static void SetUpTestCase(void);
47 static void TearDownTestCase(void);
48 void SetUp();
49 void TearDown();
50 };
51 } // namespace HiviewDFX
52 } // namespace OHOS
53
SetUpTestCase(void)54 void DfxProcessDumpTest::SetUpTestCase(void)
55 {
56 }
57
TearDownTestCase(void)58 void DfxProcessDumpTest::TearDownTestCase(void)
59 {
60 }
61
SetUp(void)62 void DfxProcessDumpTest::SetUp(void)
63 {
64 }
65
TearDown(void)66 void DfxProcessDumpTest::TearDown(void)
67 {
68 }
69
CreateMultiThreadProcess(int threadNum)70 static pid_t CreateMultiThreadProcess(int threadNum)
71 {
72 pid_t pid = fork();
73 if (pid < 0) {
74 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
75 } else if (pid == 0) {
76 (void)MultiThreadConstructor(threadNum);
77 }
78 return pid;
79 }
80
CreateMultiThreadForThreadCrash(int threadNum)81 static pid_t CreateMultiThreadForThreadCrash(int threadNum)
82 {
83 pid_t pid = fork();
84 if (pid < 0) {
85 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
86 } else if (pid == 0) {
87 (void)MultiThreadConstructorForThreadCrash(threadNum);
88 }
89 return pid;
90 }
91
CreateMultiThreadForThreadCrashWithOpen(int threadNum,int openNum)92 static pid_t CreateMultiThreadForThreadCrashWithOpen(int threadNum, int openNum)
93 {
94 pid_t pid = fork();
95 if (pid < 0) {
96 GTEST_LOG_(ERROR) << "Failed to fork new test process.";
97 } else if (pid == 0) {
98 for (int i = 0; i < openNum; ++i) {
99 fopen("/dev/null", "r");
100 }
101 (void)MultiThreadConstructorForThreadCrash(threadNum);
102 }
103 return pid;
104 }
105
CheckCppCrashKeyWords(const string & filePath,pid_t pid,int sig)106 static bool CheckCppCrashKeyWords(const string& filePath, pid_t pid, int sig)
107 {
108 if (filePath.empty() || pid <= 0) {
109 return false;
110 }
111 map<int, string> sigKey = {
112 { SIGILL, string("SIGILL") },
113 { SIGTRAP, string("SIGTRAP") },
114 { SIGABRT, string("SIGABRT") },
115 { SIGBUS, string("SIGBUS") },
116 { SIGFPE, string("SIGFPE") },
117 { SIGSEGV, string("SIGSEGV") },
118 { SIGSTKFLT, string("SIGSTKFLT") },
119 { SIGSYS, string("SIGSYS") },
120 };
121 string sigKeyword = "";
122 map<int, string>::iterator iter = sigKey.find(sig);
123 if (iter != sigKey.end()) {
124 sigKeyword = iter->second;
125 }
126 string keywords[] = {
127 "Pid:" + to_string(pid), "Uid:", "test_processdump", sigKeyword, "Tid:", "#00", "Registers:", REGISTERS,
128 "FaultStack:", "Maps:", "test_processdump"
129 };
130 int length = sizeof(keywords) / sizeof(keywords[0]);
131 int minRegIdx = 6; // 6 : index of REGISTERS
132 int count = CheckKeyWords(filePath, keywords, length, minRegIdx);
133 return count == length;
134 }
135 namespace {
CheckCppCrashExtraKeyWords(const string & filePath,std::string * keywords,int length,int minRegIdx)136 bool CheckCppCrashExtraKeyWords(const string& filePath, std::string *keywords, int length, int minRegIdx)
137 {
138 if (filePath.empty()) {
139 return false;
140 }
141 int count = CheckKeyWords(filePath, keywords, length, minRegIdx);
142 return count == length;
143 }
144 /**
145 * @tc.name: DfxProcessDumpTest001
146 * @tc.desc: test SIGILL crash
147 * @tc.type: FUNC
148 */
149 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest001, TestSize.Level2)
150 {
151 GTEST_LOG_(INFO) << "DfxProcessDumpTest001: start.";
152 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
153 sleep(1);
154 auto curTime = GetTimeMilliSeconds();
155 kill(testProcess, SIGILL);
156 sleep(3); // 3 : wait 3s to generate cpp crash file
157 auto filename = GetCppCrashFileName(testProcess);
158 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
159 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGILL));
160 GTEST_LOG_(INFO) << "DfxProcessDumpTest001: end.";
161 }
162
163 /**
164 * @tc.name: DfxProcessDumpTest002
165 * @tc.desc: test SIGTRAP crash
166 * @tc.type: FUNC
167 */
168 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest002, TestSize.Level2)
169 {
170 GTEST_LOG_(INFO) << "DfxProcessDumpTest002: start.";
171 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
172 sleep(1);
173 auto curTime = GetTimeMilliSeconds();
174 kill(testProcess, SIGTRAP);
175 sleep(3); // 3 : wait 3s to generate cpp crash file
176 auto filename = GetCppCrashFileName(testProcess);
177 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
178 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGTRAP));
179 GTEST_LOG_(INFO) << "DfxProcessDumpTest002: end.";
180 }
181
182 /**
183 * @tc.name: DfxProcessDumpTest003
184 * @tc.desc: test SIGABRT crash
185 * @tc.type: FUNC
186 */
187 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest003, TestSize.Level2)
188 {
189 GTEST_LOG_(INFO) << "DfxProcessDumpTest003: start.";
190 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
191 sleep(1);
192 auto curTime = GetTimeMilliSeconds();
193 kill(testProcess, SIGABRT);
194 sleep(3); // 3 : wait 3s to generate cpp crash file
195 auto filename = GetCppCrashFileName(testProcess);
196 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
197 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGABRT));
198 GTEST_LOG_(INFO) << "DfxProcessDumpTest003: end.";
199 }
200
201 /**
202 * @tc.name: DfxProcessDumpTest004
203 * @tc.desc: test SIGBUS crash
204 * @tc.type: FUNC
205 */
206 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest004, TestSize.Level2)
207 {
208 GTEST_LOG_(INFO) << "DfxProcessDumpTest004: start.";
209 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
210 sleep(1);
211 auto curTime = GetTimeMilliSeconds();
212 kill(testProcess, SIGBUS);
213 sleep(3); // 3 : wait 3s to generate cpp crash file
214 auto filename = GetCppCrashFileName(testProcess);
215 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
216 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGBUS));
217 GTEST_LOG_(INFO) << "DfxProcessDumpTest004: end.";
218 }
219
220 /**
221 * @tc.name: DfxProcessDumpTest005
222 * @tc.desc: test SIGFPE crash
223 * @tc.type: FUNC
224 */
225 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest005, TestSize.Level2)
226 {
227 GTEST_LOG_(INFO) << "DfxProcessDumpTest005: start.";
228 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
229 sleep(1);
230 auto curTime = GetTimeMilliSeconds();
231 kill(testProcess, SIGFPE);
232 sleep(3); // 3 : wait 3s to generate cpp crash file
233 auto filename = GetCppCrashFileName(testProcess);
234 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
235 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGFPE));
236 GTEST_LOG_(INFO) << "DfxProcessDumpTest005: end.";
237 }
238
239 /**
240 * @tc.name: DfxProcessDumpTest006
241 * @tc.desc: test SIGSEGV crash
242 * @tc.type: FUNC
243 */
244 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest006, TestSize.Level2)
245 {
246 GTEST_LOG_(INFO) << "DfxProcessDumpTest006: start.";
247 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
248 GTEST_LOG_(INFO) << "process pid:" << testProcess;
249 sleep(1);
250 auto curTime = GetTimeMilliSeconds();
251 kill(testProcess, SIGSEGV);
252 sleep(3); // 3 : wait 3s to generate cpp crash file
253 auto filename = GetCppCrashFileName(testProcess);
254 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
255 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGSEGV));
256 GTEST_LOG_(INFO) << "DfxProcessDumpTest006: end.";
257 }
258
259 /**
260 * @tc.name: DfxProcessDumpTest007
261 * @tc.desc: test SIGSTKFLT crash
262 * @tc.type: FUNC
263 */
264 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest007, TestSize.Level2)
265 {
266 GTEST_LOG_(INFO) << "DfxProcessDumpTest007: start.";
267 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
268 sleep(1);
269 auto curTime = GetTimeMilliSeconds();
270 kill(testProcess, SIGSTKFLT);
271 sleep(3); // 3 : wait 3s to generate cpp crash file
272 auto filename = GetCppCrashFileName(testProcess);
273 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
274 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGSTKFLT));
275 GTEST_LOG_(INFO) << "DfxProcessDumpTest007: end.";
276 }
277
278 /**
279 * @tc.name: DfxProcessDumpTest008
280 * @tc.desc: test SIGSYS crash
281 * @tc.type: FUNC
282 */
283 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest008, TestSize.Level2)
284 {
285 GTEST_LOG_(INFO) << "DfxProcessDumpTest008: start.";
286 pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
287 sleep(1);
288 auto curTime = GetTimeMilliSeconds();
289 kill(testProcess, SIGSYS);
290 sleep(3); // 3 : wait 3s to generate cpp crash file
291 auto filename = GetCppCrashFileName(testProcess);
292 ASSERT_EQ(std::to_string(curTime).length(), filename.length() - filename.find_last_of('-') - 1);
293 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGSYS));
294 GTEST_LOG_(INFO) << "DfxProcessDumpTest008: end.";
295 }
296
297 /**
298 * @tc.name: DfxProcessDumpTest009
299 * @tc.desc: test processdump command
300 * @tc.type: FUNC
301 * @tc.require:
302 */
303 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest009, TestSize.Level2)
304 {
305 GTEST_LOG_(INFO) << "DfxProcessDumpTest009: start.";
306 string procCMD = "processdump";
307 string procDumpLog = ExecuteCommands(procCMD);
308 string log[] = {"please use dumpcatcher"};
309 int expectNum = sizeof(log) / sizeof(log[0]);
310 int count = GetKeywordsNum(procDumpLog, log, expectNum);
311 EXPECT_EQ(count, expectNum) << "DfxProcessDumpTest009 Failed";
312 GTEST_LOG_(INFO) << "DfxProcessDumpTest009: end.";
313 }
314
315 /**
316 * @tc.name: DfxProcessDumpTest010
317 * @tc.desc: test processdump command: -p 1
318 * @tc.type: FUNC
319 * @tc.require:
320 */
321 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest010, TestSize.Level2)
322 {
323 GTEST_LOG_(INFO) << "DfxProcessDumpTest010: start.";
324 string procCMD = "processdump -p 1";
325 string procDumpLog = ExecuteCommands(procCMD);
326 string log[] = {"please use dumpcatcher"};
327 int expectNum = sizeof(log) / sizeof(log[0]);
328 int count = GetKeywordsNum(procDumpLog, log, expectNum);
329 EXPECT_EQ(count, expectNum) << "DfxProcessDumpTest010 Failed";
330 GTEST_LOG_(INFO) << "DfxProcessDumpTest010: end.";
331 }
332
333 /**
334 * @tc.name: DfxProcessDumpTest011
335 * @tc.desc: Testing the sub thread crash of multithreaded programs
336 * @tc.type: FUNC
337 */
338 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest011, TestSize.Level2)
339 {
340 GTEST_LOG_(INFO) << "DfxProcessDumpTest011: start.";
341 pid_t testProcess = CreateMultiThreadForThreadCrash(10); // 10 : create a process with ten threads
342 GTEST_LOG_(INFO) << "process pid:" << testProcess;
343 sleep(3); // 3 : wait 3s to generate cpp crash file
344 auto filename = GetCppCrashFileName(testProcess);
345 ASSERT_TRUE(CheckCppCrashKeyWords(filename, testProcess, SIGSEGV));
346 GTEST_LOG_(INFO) << "DfxProcessDumpTest011: end.";
347 }
348
349
350 /**
351 * @tc.name: DfxProcessDumpTest012
352 * @tc.desc: Testing new add key word
353 * @tc.type: FUNC
354 */
355 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest012, TestSize.Level2)
356 {
357 GTEST_LOG_(INFO) << "DfxProcessDumpTest012: start.";
358 pid_t testProcess = CreateMultiThreadForThreadCrash(10); // 10 : create a process with ten threads
359 GTEST_LOG_(INFO) << "process pid:" << testProcess;
360 sleep(3); // 3 : wait 3s to generate cpp crash file
361 auto filename = GetCppCrashFileName(testProcess);
362 string keywords[] = {
363 "time", "OpenFiles:"
364 };
365 int length = sizeof(keywords) / sizeof(keywords[0]);
366 int minRegIdx = -1; // -1 : no not check register value
367 ASSERT_TRUE(CheckCppCrashExtraKeyWords(filename, keywords, length, minRegIdx));
368 GTEST_LOG_(INFO) << "DfxProcessDumpTest012: end.";
369 }
370
371 /**
372 * @tc.name: DfxProcessDumpTest013
373 * @tc.desc: Testing new add key word
374 * @tc.type: FUNC
375 */
376 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest013, TestSize.Level2)
377 {
378 GTEST_LOG_(INFO) << "DfxProcessDumpTest013: start.";
379 int openNum = 128;
380 pid_t testProcess = CreateMultiThreadForThreadCrashWithOpen(10, openNum); // 10 : create a process with ten threads
381 GTEST_LOG_(INFO) << "process pid:" << testProcess;
382 sleep(3); // 3 : wait 3s to generate cpp crash file
383 auto filename = GetCppCrashFileName(testProcess);
384 string keywords[openNum];
385 string str = "FILE*";
386 for (int i = 0; i < openNum; ++i) {
387 keywords[i] = str;
388 }
389 int length = sizeof(keywords) / sizeof(keywords[0]);
390 int minRegIdx = -1; // -1 : no not check register value
391 ASSERT_TRUE(CheckCppCrashExtraKeyWords(filename, keywords, length, minRegIdx));
392 GTEST_LOG_(INFO) << "DfxProcessDumpTest013: end.";
393 }
394
395 /**
396 * @tc.name: DfxProcessDumpTest014
397 * @tc.desc: Testing dlopen and dlsym interfaces
398 * @tc.type: FUNC
399 */
400 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest014, TestSize.Level2)
401 {
402 GTEST_LOG_(INFO) << "DfxProcessDumpTest014: start.";
403 void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
404 ASSERT_TRUE(handle) << "Failed to dlopen libfaultlogger";
405 auto addFaultLog = reinterpret_cast<void (*)(FaultLogInfoInner*)>(dlsym(handle, "AddFaultLog"));
406 ASSERT_TRUE(addFaultLog) << "Failed to dlsym addFaultLog";
407 FaultLogInfoInner info;
408 info.time = time(NULL);
409 info.id = 0;
410 info.pid = 1;
411 info.pipeFd = -1;
412 info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
413 info.module = "";
414 info.reason = "";
415 info.summary = "";
416 info.registers = "";
417 addFaultLog(&info);
418 dlclose(handle);
419 GTEST_LOG_(INFO) << "DfxProcessDumpTest01: end.";
420 }
421
422 /**
423 * @tc.name: DfxProcessDumpTest015
424 * @tc.desc: Testing dlopen and dlsym RecordAppExitReason
425 * @tc.type: FUNC
426 */
427 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest015, TestSize.Level2)
428 {
429 GTEST_LOG_(INFO) << "DfxProcessDumpTest015: start.";
430 void* handle = dlopen("libability_manager_c.z.so", RTLD_LAZY | RTLD_NODELETE);
431 ASSERT_TRUE(handle) << "Failed to dlopen libability_manager_c";
432 RecordAppExitReason recordAppExitReason = (RecordAppExitReason)dlsym(handle, "RecordAppExitReason");
433 ASSERT_TRUE(recordAppExitReason) << "Failed to dlsym RecordAppExitReason";
434 string reason_ = "reason";
435 const int cppCrashExitReason = 2;
436 recordAppExitReason(cppCrashExitReason, reason_.c_str());
437 dlclose(handle);
438 GTEST_LOG_(INFO) << "DfxProcessDumpTest015: end.";
439 }
440
441 /**
442 * @tc.name: DfxProcessDumpTest016
443 * @tc.desc: Testing InitDebugLog Function
444 * @tc.type: FUNC
445 */
446 HWTEST_F(DfxProcessDumpTest, DfxProcessDumpTest016, TestSize.Level2)
447 {
448 GTEST_LOG_(INFO) << "DfxProcessDumpTest016: start.";
449 pid_t pid = fork();
450 ASSERT_TRUE(pid >= 0);
451 if (pid == 0) {
452 sleep(3); // 3 : sleep 3 seconds
453 }
454 char msg[] = "test log";
455 DfxLogToSocket(msg);
456 kill(pid, SIGSEGV);
457 InitDebugLog(FaultLoggerType::CPP_CRASH, pid, pid, 0);
458 CloseDebugLog();
459 GTEST_LOG_(INFO) << "DfxProcessDumpTest016: end.";
460 }
461 }