• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 <string>
18 #include <unistd.h>
19 #include <vector>
20 
21 #include "dfx_buffer_writer.h"
22 #include "decorative_dump_info.h"
23 #include "dfx_process.h"
24 #include "dfx_define.h"
25 #include "dfx_test_util.h"
26 #include "dfx_util.h"
27 #include "key_thread_dump_info.h"
28 #include "procinfo.h"
29 #include "multithread_constructor.h"
30 
31 
32 using namespace OHOS::HiviewDFX;
33 using namespace testing::ext;
34 using namespace std;
35 
36 namespace OHOS {
37 namespace HiviewDFX {
38 class ThreadDumpInfoTest : public testing::Test {
39 public:
40     static void SetUpTestCase(void);
TearDownTestCase(void)41     static void TearDownTestCase(void) {}
42     void SetUp();
TearDown()43     void TearDown() {}
44     static int WriteLogFunc(int32_t fd, const char *buf, size_t len);
45     static std::string result;
46 };
47 } // namespace HiviewDFX
48 } // namespace OHOS
49 
50 std::string ThreadDumpInfoTest::result = "";
51 
SetUpTestCase(void)52 void ThreadDumpInfoTest::SetUpTestCase(void)
53 {
54     result = "";
55 }
56 
SetUp(void)57 void ThreadDumpInfoTest::SetUp(void)
58 {
59     DfxBufferWriter::GetInstance().SetWriteFunc(ThreadDumpInfoTest::WriteLogFunc);
60 }
61 
WriteLogFunc(int32_t fd,const char * buf,size_t len)62 int ThreadDumpInfoTest::WriteLogFunc(int32_t fd, const char *buf, size_t len)
63 {
64     ThreadDumpInfoTest::result.append(std::string(buf, len));
65     return 0;
66 }
67 
68 namespace {
69 pid_t g_childTid = 0;
SleepThread(void * argv)70 void *SleepThread(void *argv)
71 {
72     int threadID = *(int*)argv;
73     printf("create MultiThread %d", threadID);
74 
75     const int sleepTime = 10;
76     g_childTid = gettid();
77     sleep(sleepTime);
78     return nullptr;
79 }
80 
81 /**
82  * @tc.name: ThreadDumpInfoTest001
83  * @tc.desc: test KeyThreadDumpInfo dumpcatch
84  * @tc.type: FUNC
85  */
86 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest001, TestSize.Level2)
87 {
88     GTEST_LOG_(INFO) << "ThreadDumpInfoTest001: start.";
89     // dumpcatch -p
90     pid_t pid = fork();
91     if (pid < 0) {
92         GTEST_LOG_(ERROR) << "Failed to fork new test process.";
93     } else if (pid == 0) {
94         sleep(3); // 3 : sleep 3 seconds
95         exit(0);
96     }
97     pid_t tid = pid;
98     pid_t nsPid = pid;
99     ProcessDumpRequest request = {
100         .type = ProcessDumpType::DUMP_TYPE_DUMP_CATCH,
101         .tid = tid,
102         .pid = pid,
103         .nsPid = pid,
104     };
105     DfxProcess process;
106     process.InitProcessInfo(pid, nsPid, getuid(), "");
107     process.SetVmPid(pid);
108     process.InitKeyThread(request);
109     process.GetKeyThread()->SetThreadRegs(DfxRegs::CreateRemoteRegs(pid)); // can not get context, so create regs self
110     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
111     unwinder.EnableFillFrames(false);
112     KeyThreadDumpInfo dumpInfo;
113     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), 0);
114     dumpInfo.Symbolize(process, unwinder);
115     dumpInfo.Print(process, request, unwinder);
116     std::vector<std::string> keyWords = {
117         "Tid:",
118         to_string(tid),
119         "Name:",
120         "#00",
121         "#01",
122     };
123     for (const std::string& keyWord : keyWords) {
124         EXPECT_TRUE(CheckContent(result, keyWord, true));
125     }
126     process.Detach();
127     GTEST_LOG_(INFO) << "ThreadDumpInfoTest001: end.";
128 }
129 
130 /**
131  * @tc.name: ThreadDumpInfoTest002
132  * @tc.desc: test KeyThreadDumpInfo dumpcatch single thread
133  * @tc.type: FUNC
134  */
135 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest002, TestSize.Level2)
136 {
137     GTEST_LOG_(INFO) << "ThreadDumpInfoTest002: start.";
138     // dumpcatch -p -t
139     pid_t pid = fork();
140     if (pid < 0) {
141         GTEST_LOG_(ERROR) << "Failed to fork new test process.";
142     } else if (pid == 0) {
143         pthread_t childThread;
144         int threadID[1] = {1};
145         pthread_create(&childThread, NULL, SleepThread, &threadID[0]);
146         pthread_detach(childThread);
147         sleep(3); // 3 : sleep 3 seconds
148         exit(0);
149     }
150     sleep(1);
151     pid_t tid = pid;
152     pid_t nsPid = pid;
153     ProcessDumpRequest request = {
154         .type = ProcessDumpType::DUMP_TYPE_DUMP_CATCH,
155         .tid = tid,
156         .pid = pid,
157         .nsPid = pid,
158     };
159     std::vector<int> tids;
160     std::vector<int> nstids;
161     EXPECT_TRUE(GetTidsByPid(pid, tids, nstids));
162     request.siginfo.si_value.sival_int = nstids[nstids.size() - 1];
163     DfxProcess process;
164     process.InitProcessInfo(pid, nsPid, getuid(), "");
165     process.SetVmPid(pid);
166     process.InitKeyThread(request);
167     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
168     unwinder.EnableFillFrames(false);
169     KeyThreadDumpInfo dumpInfo;
170     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), 0);
171     dumpInfo.Symbolize(process, unwinder);
172     dumpInfo.Print(process, request, unwinder);
173     std::vector<std::string> keyWords = {
174         "Tid:",
175         to_string(g_childTid),
176         "Name:",
177         "#00",
178         "#01",
179     };
180     for (const std::string& keyWord : keyWords) {
181         EXPECT_TRUE(CheckContent(result, keyWord, true));
182     }
183     process.Detach();
184     GTEST_LOG_(INFO) << "ThreadDumpInfoTest002: end.";
185 }
186 
187 /**
188  * @tc.name: ThreadDumpInfoTest003
189  * @tc.desc: test KeyThreadDumpInfo cppcrash
190  * @tc.type: FUNC
191  */
192 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest003, TestSize.Level2)
193 {
194     GTEST_LOG_(INFO) << "ThreadDumpInfoTest003: start.";
195     pid_t pid = fork();
196     if (pid < 0) {
197         GTEST_LOG_(ERROR) << "Failed to fork new test process.";
198     } else if (pid == 0) {
199         sleep(3); // 3 : sleep 3 seconds
200         exit(0);
201     }
202     pid_t tid = pid;
203     pid_t nsPid = pid;
204     ProcessDumpRequest request = {
205         .type = ProcessDumpType::DUMP_TYPE_CPP_CRASH,
206         .tid = tid,
207         .pid = pid,
208         .nsPid = pid,
209     };
210     DfxProcess process;
211     process.InitProcessInfo(pid, nsPid, getuid(), "");
212     process.SetVmPid(pid);
213     process.InitKeyThread(request);
214     process.GetKeyThread()->SetThreadRegs(DfxRegs::CreateRemoteRegs(pid)); // can not get context, so create regs self
215     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
216     unwinder.EnableFillFrames(false);
217     KeyThreadDumpInfo dumpInfo;
218     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), 0);
219     dumpInfo.Symbolize(process, unwinder);
220     dumpInfo.Print(process, request, unwinder);
221     std::vector<std::string> keyWords = {
222         "Fault thread info:",
223         "Tid:",
224         to_string(tid),
225         "#00",
226         "#01",
227     };
228     for (const std::string& keyWord : keyWords) {
229         EXPECT_TRUE(CheckContent(result, keyWord, true));
230     }
231     GTEST_LOG_(INFO) << "ThreadDumpInfoTest003: end.";
232 }
233 
234 /**
235  * @tc.name: ThreadDumpInfoTest004
236  * @tc.desc: test other thread dump info in cppcrash type
237  * @tc.type: FUNC
238  */
239 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest004, TestSize.Level2)
240 {
241     GTEST_LOG_(INFO) << "ThreadDumpInfoTest004: start.";
242     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
243     sleep(1);
244     pid_t pid = testProcess;
245     pid_t tid = testProcess;
246     pid_t nsPid = testProcess;
247     ProcessDumpRequest request = {
248         .type = ProcessDumpType::DUMP_TYPE_CPP_CRASH,
249         .tid = tid,
250         .pid = pid,
251         .nsPid = pid,
252     };
253     DfxProcess process;
254     process.InitProcessInfo(pid, nsPid, getuid(), "");
255     process.SetVmPid(pid);
256     process.InitOtherThreads(0);
257     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
258     unwinder.EnableFillFrames(false);
259     OtherThreadDumpInfo dumpInfo;
260     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), 0);
261     dumpInfo.Symbolize(process, unwinder);
262     dumpInfo.Print(process, request, unwinder);
263     std::vector<std::string> keyWords = {
264         "Other thread info:",
265         "Tid:",
266         "#00",
267         "#01",
268     };
269     for (const std::string& keyWord : keyWords) {
270         EXPECT_TRUE(CheckContent(result, keyWord, true));
271     }
272     process.Detach();
273     kill(pid, SIGKILL);
274     GTEST_LOG_(INFO) << "ThreadDumpInfoTest004: end.";
275 }
276 
277 /**
278  * @tc.name: ThreadDumpInfoTest005
279  * @tc.desc: test other thread dump info in dumpcatch type
280  * @tc.type: FUNC
281  */
282 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest005, TestSize.Level2)
283 {
284     GTEST_LOG_(INFO) << "ThreadDumpInfoTest005: start.";
285     pid_t testProcess = CreateMultiThreadProcess(10); // 10 : create a process with ten threads
286     sleep(1);
287     pid_t pid = testProcess;
288     pid_t tid = testProcess;
289     pid_t nsPid = testProcess;
290     ProcessDumpRequest request = {
291         .type = ProcessDumpType::DUMP_TYPE_DUMP_CATCH,
292         .tid = tid,
293         .pid = pid,
294         .nsPid = pid,
295     };
296     DfxProcess process;
297     process.InitProcessInfo(pid, nsPid, getuid(), "");
298     process.SetVmPid(pid);
299     process.InitOtherThreads(0);
300     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
301     unwinder.EnableFillFrames(false);
302     OtherThreadDumpInfo dumpInfo;
303     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), 0);
304     dumpInfo.Symbolize(process, unwinder);
305     dumpInfo.Print(process, request, unwinder);
306     std::vector<std::string> keyWords = {
307         "Tid:",
308         "#00",
309         "#01",
310     };
311     for (const std::string& keyWord : keyWords) {
312         EXPECT_TRUE(CheckContent(result, keyWord, true));
313     }
314     process.Detach();
315     kill(pid, SIGKILL);
316     GTEST_LOG_(INFO) << "ThreadDumpInfoTest005: end.";
317 }
318 
319 /**
320  * @tc.name: ThreadDumpInfoTest006
321  * @tc.desc: test all thread dump info
322  * @tc.type: FUNC
323  */
324 HWTEST_F(ThreadDumpInfoTest, ThreadDumpInfoTest006, TestSize.Level2)
325 {
326     GTEST_LOG_(INFO) << "ThreadDumpInfoTest006: start.";
327     int threadCount = 10;
328     pid_t pid = CreateMultiThreadProcess(threadCount);
329     sleep(1);
330     pid_t nsPid = pid;
331     ProcessDumpRequest request = {
332         .type = ProcessDumpType::DUMP_TYPE_DUMP_CATCH,
333         .tid = pid,
334         .pid = pid,
335         .nsPid = pid,
336     };
337     DfxProcess process;
338     process.InitProcessInfo(pid, nsPid, getuid(), "");
339     process.InitKeyThread(request);
340     process.SetVmPid(pid);
341     process.GetKeyThread()->SetThreadRegs(DfxRegs::CreateRemoteRegs(pid)); // can not get context, so create regs self
342     process.InitOtherThreads(pid);
343     Unwinder unwinder(pid, nsPid, request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
344     unwinder.EnableFillFrames(false);
345     std::shared_ptr<DumpInfo> keyThreadDumpInfo = std::make_shared<KeyThreadDumpInfo>();
346     OtherThreadDumpInfo dumpInfo;
347     dumpInfo.SetDumpInfo(keyThreadDumpInfo);
348     EXPECT_GT(dumpInfo.UnwindStack(process, request, unwinder), threadCount);
349     dumpInfo.Symbolize(process, unwinder);
350     dumpInfo.Print(process, request, unwinder);
351     std::vector<std::string> keyWords = {
352         "Tid:",
353         to_string(pid),
354         "#00",
355         "#01",
356     };
357     for (const std::string& keyWord : keyWords) {
358         EXPECT_TRUE(CheckContent(result, keyWord, true));
359     }
360     process.Detach();
361     kill(pid, SIGKILL);
362     GTEST_LOG_(INFO) << "ThreadDumpInfoTest006: end.";
363 }
364 }
365