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 }