1 /*
2  * Copyright (c) 2022-2024 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 
18 #include <cstdio>
19 #include <cstdlib>
20 #include <memory>
21 #include <mutex>
22 #include <thread>
23 
24 #include <dlfcn.h>
25 #include <fcntl.h>
26 #include <securec.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29 
30 #include "backtrace_local.h"
31 #include "backtrace_local_thread.h"
32 #include "dfx_frame_formatter.h"
33 #include "dfx_kernel_stack.h"
34 #include "dfx_test_util.h"
35 #include "elapsed_time.h"
36 
37 using namespace testing;
38 using namespace testing::ext;
39 
40 namespace OHOS {
41 namespace HiviewDFX {
42 #undef LOG_DOMAIN
43 #undef LOG_TAG
44 #define LOG_TAG "DfxBacktraceLocalTest"
45 #define LOG_DOMAIN 0xD002D11
46 #define DEFAULT_MAX_FRAME_NUM 256
47 #define MIN_FRAME_NUM 2
48 
49 class BacktraceLocalTest : public testing::Test {
50 public:
51     static void SetUpTestCase();
52     static void TearDownTestCase();
53     void SetUp();
54     void TearDown();
55 
56     uint32_t fdCount;
57     uint32_t mapsCount;
58     uint64_t memCount;
59 
60     static uint32_t fdCountTotal;
61     static uint32_t mapsCountTotal;
62     static uint64_t memCountTotal;
63 };
64 
65 uint32_t BacktraceLocalTest::fdCountTotal = 0;
66 uint32_t BacktraceLocalTest::mapsCountTotal = 0;
67 uint64_t BacktraceLocalTest::memCountTotal = 0;
68 
69 
SetUpTestCase()70 void BacktraceLocalTest::SetUpTestCase()
71 {
72     BacktraceLocalTest::fdCountTotal = GetSelfFdCount();
73     BacktraceLocalTest::mapsCountTotal = GetSelfMapsCount();
74     BacktraceLocalTest::memCountTotal = GetSelfMemoryCount();
75 }
76 
TearDownTestCase()77 void BacktraceLocalTest::TearDownTestCase()
78 {
79     CheckResourceUsage(fdCountTotal, mapsCountTotal, memCountTotal);
80 }
81 
SetUp()82 void BacktraceLocalTest::SetUp()
83 {
84     fdCount = GetSelfFdCount();
85     mapsCount = GetSelfMapsCount();
86     memCount = GetSelfMemoryCount();
87 }
88 
TearDown()89 void BacktraceLocalTest::TearDown()
90 {
91     CheckResourceUsage(fdCount, mapsCount, memCount);
92 }
93 
94 /**
95  * @tc.name: BacktraceLocalTest001
96  * @tc.desc: test get backtrace of current thread
97  * @tc.type: FUNC
98  */
99 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest001, TestSize.Level2)
100 {
101     GTEST_LOG_(INFO) << "BacktraceLocalTest001: start.";
102     ElapsedTime counter;
103     auto unwinder = std::make_shared<Unwinder>();
104     BacktraceLocalThread thread(BACKTRACE_CURRENT_THREAD, unwinder);
105     ASSERT_EQ(true, thread.Unwind(0));
106     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
107     const auto& frames = thread.GetFrames();
108     ASSERT_GT(frames.size(), 0);
109     GTEST_LOG_(INFO) << thread.GetFormattedStr();
110     GTEST_LOG_(INFO) << "BacktraceLocalTest001: end.";
111 }
112 
113 int32_t g_tid = 0;
114 std::mutex g_mutex;
Test002()115 __attribute__((noinline)) void Test002()
116 {
117     printf("Test002\n");
118     g_mutex.lock();
119     g_mutex.unlock();
120 }
121 
Test001()122 __attribute__((noinline)) void Test001()
123 {
124     g_tid = gettid();
125     printf("Test001:%d\n", g_tid);
126     Test002();
127 }
128 
129 /**
130  * @tc.name: BacktraceLocalTest003
131  * @tc.desc: test get backtrace of a child thread
132  * @tc.type: FUNC
133  */
134 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest003, TestSize.Level2)
135 {
136     GTEST_LOG_(INFO) << "BacktraceLocalTest003: start.";
137     g_mutex.lock();
138     std::thread backtraceThread(Test001);
139     sleep(1);
140     if (g_tid <= 0) {
141         FAIL() << "Failed to create child thread.\n";
142     }
143 
144     ElapsedTime counter;
145     auto unwinder = std::make_shared<Unwinder>();
146     BacktraceLocalThread thread(g_tid, unwinder);
147     ASSERT_EQ(true, thread.Unwind(0));
148     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
149     const auto& frames = thread.GetFrames();
150     ASSERT_GT(frames.size(), 0);
151     auto backtraceStr = thread.GetFormattedStr(false);
152     ASSERT_GT(backtraceStr.size(), 0);
153     GTEST_LOG_(INFO) << "backtraceStr:\n" << backtraceStr;
154 
155     std::string str;
156     auto ret = GetBacktraceStringByTid(str, g_tid, 0, false);
157     ASSERT_TRUE(ret);
158     GTEST_LOG_(INFO) << "GetBacktraceStringByTid:\n" << str;
159     g_mutex.unlock();
160     g_tid = 0;
161     if (backtraceThread.joinable()) {
162         backtraceThread.join();
163     }
164     GTEST_LOG_(INFO) << "BacktraceLocalTest003: end.";
165 }
166 
167 /**
168  * @tc.name: BacktraceLocalTest004
169  * @tc.desc: test get backtrace of a child thread
170  * @tc.type: FUNC
171  */
172 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest004, TestSize.Level2)
173 {
174     GTEST_LOG_(INFO) << "BacktraceLocalTest004: start.";
175     g_mutex.lock();
176     std::thread backtraceThread(Test001);
177     sleep(1);
178     if (g_tid <= 0) {
179         FAIL() << "Failed to create child thread.\n";
180     }
181 
182     std::string str;
183     auto ret = GetBacktraceStringByTid(str, g_tid, 0, false);
184     ASSERT_TRUE(ret);
185     string log[] = {"#00", "backtrace_local", "Tid:", "Name"};
186     log[2] = log[2] + std::to_string(g_tid);
187     int logSize = sizeof(log) / sizeof(log[0]);
188     int count = GetKeywordsNum(str, log, logSize);
189     EXPECT_EQ(count, logSize) << "BacktraceLocalTest004 Failed";
190     GTEST_LOG_(INFO) << "GetBacktraceStringByTid:\n" << str;
191     g_mutex.unlock();
192     g_tid = 0;
193     if (backtraceThread.joinable()) {
194         backtraceThread.join();
195     }
196     GTEST_LOG_(INFO) << "BacktraceLocalTest004: end.";
197 }
198 
199 /**
200  * @tc.name: BacktraceLocalTest005
201  * @tc.desc: test get backtrace of current process
202  * @tc.type: FUNC
203  */
204 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest005, TestSize.Level2)
205 {
206     GTEST_LOG_(INFO) << "BacktraceLocalTest005: start.";
207     g_mutex.lock();
208     std::thread backtraceThread(Test001);
209     sleep(1);
210     if (g_tid <= 0) {
211         FAIL() << "Failed to create child thread.\n";
212     }
213 
214     std::string stacktrace = GetProcessStacktrace();
215     ASSERT_GT(stacktrace.size(), 0);
216     GTEST_LOG_(INFO) << stacktrace;
217 
218     if (stacktrace.find("backtrace_local_test") == std::string::npos) {
219         FAIL() << "Failed to find pid key word.\n";
220     }
221     if (stacktrace.find("#01") == std::string::npos) {
222         FAIL() << "Failed to find stack key word.\n";
223     }
224 
225     g_mutex.unlock();
226     g_tid = 0;
227     if (backtraceThread.joinable()) {
228         backtraceThread.join();
229     }
230     GTEST_LOG_(INFO) << "BacktraceLocalTest005: end.";
231 }
232 
233 /**
234  * @tc.name: BacktraceLocalTest006
235  * @tc.desc: test GetTrace C interface
236  * @tc.type: FUNC
237  */
238 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest006, TestSize.Level2)
239 {
240     GTEST_LOG_(INFO) << "BacktraceLocalTest006: start.";
241     const char* trace = GetTrace();
242     std::string stacktrace(trace);
243     GTEST_LOG_(INFO) << stacktrace;
244     ASSERT_TRUE(stacktrace.find("#00") != std::string::npos);
245     ASSERT_TRUE(stacktrace.find("pc") != std::string::npos);
246     ASSERT_TRUE(stacktrace.find("backtrace_local_test") != std::string::npos);
247     GTEST_LOG_(INFO) << "BacktraceLocalTest006: end.";
248 }
249 
250 /**
251  * @tc.name: BacktraceLocalTest007
252  * @tc.desc: test skip two stack frames and verify stack frame
253  * @tc.type: FUNC
254  */
255 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest007, TestSize.Level2)
256 {
257     GTEST_LOG_(INFO) << "BacktraceLocalTest007: start.";
258     ElapsedTime counter;
259     auto unwinder = std::make_shared<Unwinder>();
260     BacktraceLocalThread oldthread(BACKTRACE_CURRENT_THREAD, unwinder);
261     ASSERT_EQ(true, oldthread.Unwind(0));
262     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
263     const auto& oldframes = oldthread.GetFrames();
264     ASSERT_GT(oldframes.size(), MIN_FRAME_NUM);
265     std::string oldframe = DfxFrameFormatter::GetFrameStr(oldframes[MIN_FRAME_NUM]);
266     GTEST_LOG_(INFO) << oldthread.GetFormattedStr();
267     BacktraceLocalThread newthread(BACKTRACE_CURRENT_THREAD, unwinder);
268     ASSERT_EQ(true, newthread.Unwind(0, DEFAULT_MAX_FRAME_NUM, MIN_FRAME_NUM));
269     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
270     const auto& newframes = newthread.GetFrames();
271     GTEST_LOG_(INFO) << newthread.GetFormattedStr();
272     ASSERT_EQ(oldframes.size(), newframes.size() + MIN_FRAME_NUM);
273     std::string newframe = DfxFrameFormatter::GetFrameStr(newframes[0]);
274     size_t skip = 3; // skip #0x
275     ASSERT_EQ(oldframe.erase(0, skip), newframe.erase(0, skip));
276     GTEST_LOG_(INFO) << "BacktraceLocalTest007: end.";
277 }
278 
279 /**
280  * @tc.name: BacktraceLocalTest008
281  * @tc.desc: test skip all stack frames
282  * @tc.type: FUNC
283  */
284 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest008, TestSize.Level2)
285 {
286     GTEST_LOG_(INFO) << "BacktraceLocalTest008: start.";
287     ElapsedTime counter;
288     auto unwinder = std::make_shared<Unwinder>();
289     BacktraceLocalThread oldthread(BACKTRACE_CURRENT_THREAD, unwinder);
290     ASSERT_EQ(true, oldthread.Unwind(0));
291     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
292     const auto& oldframes = oldthread.GetFrames();
293     ASSERT_GT(oldframes.size(), 0);
294     size_t oldsize = oldframes.size() - 1;
295     GTEST_LOG_(INFO) << oldthread.GetFormattedStr();
296     BacktraceLocalThread newthread(BACKTRACE_CURRENT_THREAD, unwinder);
297     ASSERT_EQ(true, newthread.Unwind(0, DEFAULT_MAX_FRAME_NUM, oldsize));
298     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
299     const auto& newframes = newthread.GetFrames();
300     GTEST_LOG_(INFO) << newthread.GetFormattedStr();
301     ASSERT_EQ(oldframes.size(), newframes.size() + oldsize);
302     GTEST_LOG_(INFO) << "BacktraceLocalTest008: end.";
303 }
304 
305 
306 /**
307  * @tc.name: BacktraceLocalTest009
308  * @tc.desc: test skip stack frames exceeding the length
309  * @tc.type: FUNC
310  */
311 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest009, TestSize.Level2)
312 {
313     GTEST_LOG_(INFO) << "BacktraceLocalTest009: start.";
314     ElapsedTime counter;
315     auto unwinder = std::make_shared<Unwinder>();
316     BacktraceLocalThread oldthread(BACKTRACE_CURRENT_THREAD, unwinder);
317     ASSERT_EQ(true, oldthread.Unwind(0, DEFAULT_MAX_FRAME_NUM, -1));
318     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
319     const auto& oldframes = oldthread.GetFrames();
320     ASSERT_GT(oldframes.size(), MIN_FRAME_NUM);
321     GTEST_LOG_(INFO) << oldthread.GetFormattedStr();
322     BacktraceLocalThread newthread(BACKTRACE_CURRENT_THREAD, unwinder);
323     ASSERT_EQ(true, newthread.Unwind(0, DEFAULT_MAX_FRAME_NUM, DEFAULT_MAX_FRAME_NUM));
324     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
325     const auto& newframes = newthread.GetFrames();
326     GTEST_LOG_(INFO) << newthread.GetFormattedStr();
327     ASSERT_EQ(oldframes.size(), newframes.size());
328     GTEST_LOG_(INFO) << "BacktraceLocalTest009: end.";
329 }
330 
331 /**
332  * @tc.name: BacktraceLocalTest010
333  * @tc.desc: test get backtrace of current thread
334  * @tc.type: FUNC
335  */
336 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest010, TestSize.Level2)
337 {
338     GTEST_LOG_(INFO) << "BacktraceLocalTest010: start.";
339     std::string frame;
340     ASSERT_EQ(true, GetBacktrace(frame, 0, false, DEFAULT_MAX_FRAME_NUM));
341     int start = frame.find("#00");
342     int end = frame.find("#01");
343     std::string str = frame.substr(start, end - start);
344     GTEST_LOG_(INFO) << "frame" << frame;
345     GTEST_LOG_(INFO) << "str" << str;
346     std::string keyword = "libbacktrace_local.so";
347 #if defined(BACKTRACE_LOCAL_TEST_STATIC)
348     keyword = "backtrace_local_test_static";
349 #endif
350     ASSERT_TRUE(str.find(keyword) != std::string::npos);
351     GTEST_LOG_(INFO) << "BacktraceLocalTest010: end.";
352 }
353 
354 /**
355  * @tc.name: BacktraceLocalTest011
356  * @tc.desc: test get thread kernel stack
357  * @tc.type: FUNC
358  */
359 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest011, TestSize.Level2)
360 {
361     GTEST_LOG_(INFO) << "BacktraceLocalTest011: start.";
362     std::string res = ExecuteCommands("uname");
363     if (res.find("Linux") != std::string::npos) {
364         return;
365     }
366     std::string kernelStack;
367     ASSERT_EQ(DfxGetKernelStack(gettid(), kernelStack), 0);
368     DfxThreadStack threadStack;
369     ASSERT_TRUE(FormatThreadKernelStack(kernelStack, threadStack));
370     ASSERT_GT(threadStack.frames.size(), 0);
371     for (auto const& frame : threadStack.frames) {
372         auto line = DfxFrameFormatter::GetFrameStr(frame);
373         ASSERT_NE(line.find("#"), std::string::npos);
374         GTEST_LOG_(INFO) << line;
375     }
376     GTEST_LOG_(INFO) << "BacktraceLocalTest011: end.";
377 }
378 
379 /**
380  * @tc.name: BacktraceLocalTest012
381  * @tc.desc: test BacktraceLocal abnormal scenario
382  * @tc.type: FUNC
383  */
384 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest012, TestSize.Level2)
385 {
386     GTEST_LOG_(INFO) << "BacktraceLocalTest012: start.";
387     std::shared_ptr<Unwinder> unwinder1 = nullptr;
388     const int tid = -2;
389     BacktraceLocalThread backtrace1(tid, unwinder1);
390     bool ret = backtrace1.Unwind(false, 0, 0);
391     ASSERT_EQ(ret, false);
392     std::shared_ptr<Unwinder> unwinder2 = std::make_shared<Unwinder>();
393     BacktraceLocalThread backtrace2(tid, unwinder2);
394     ret = backtrace2.Unwind(false, 0, 0);
395     ASSERT_EQ(ret, false);
396     std::string str = backtrace2.GetFormattedStr(false);
397     ASSERT_EQ(str, "");
398     GTEST_LOG_(INFO) << "BacktraceLocalTest012: end.";
399 }
400 } // namespace HiviewDFX
401 } // namepsace OHOS
402