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 }