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