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