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