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