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