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 <directory_ex.h>
20 #include <fcntl.h>
21 #include <malloc.h>
22 #include <string_ex.h>
23 #include <thread>
24 #include <unistd.h>
25 
26 #include "backtrace_local.h"
27 #include "dfx_test_util.h"
28 #include "file_util.h"
29 
30 using namespace testing;
31 using namespace testing::ext;
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 #undef LOG_DOMAIN
36 #undef LOG_TAG
37 #define LOG_TAG "DfxBacktraceUtilsTest"
38 #define LOG_DOMAIN 0xD002D11
39 
40 #define TEST_TEMP_FILE "/data/test/testfile"
41 /*
42 expected output log should be like this(aarch64):
43     Backtrace: #01 pc 000000000000d2f8 /data/test/backtrace_utils_test
44     Backtrace: #02 pc 000000000000d164 /data/test/backtrace_utils_test
45     Backtrace: #03 pc 000000000000c86c /data/test/backtrace_utils_test
46     Backtrace: #04 pc 0000000000013f88 /data/test/backtrace_utils_test
47     Backtrace: #05 pc 00000000000148a4 /data/test/backtrace_utils_test
48     Backtrace: #06 pc 0000000000015140 /data/test/backtrace_utils_test
49     Backtrace: #07 pc 00000000000242d8 /data/test/backtrace_utils_test
50     Backtrace: #08 pc 0000000000023bd8 /data/test/backtrace_utils_test
51     Backtrace: #09 pc 000000000000df68 /data/test/backtrace_utils_test
52     Backtrace: #10 pc 00000000000dcf74 /system/lib/ld-musl-aarch64.so.1
53     Backtrace: #11 pc 000000000000c614 /data/test/backtrace_utils_test
54 */
55 
56 class BacktraceUtilsTest : public testing::Test {
57 public:
58     static void SetUpTestCase();
59     static void TearDownTestCase();
60     void SetUp();
61     void TearDown();
62 
63     uint32_t fdCount;
64     uint32_t mapsCount;
65     uint64_t memCount;
66 
67     static uint32_t fdCountTotal;
68     static uint32_t mapsCountTotal;
69     static uint64_t memCountTotal;
70 };
71 
72 uint32_t BacktraceUtilsTest::fdCountTotal = 0;
73 uint32_t BacktraceUtilsTest::mapsCountTotal = 0;
74 uint64_t BacktraceUtilsTest::memCountTotal = 0;
75 
SetUpTestCase()76 void BacktraceUtilsTest::SetUpTestCase()
77 {
78     // get memory/fd/maps
79     BacktraceUtilsTest::fdCountTotal = GetSelfFdCount();
80     BacktraceUtilsTest::mapsCountTotal = GetSelfMapsCount();
81     BacktraceUtilsTest::memCountTotal = GetSelfMemoryCount();
82 }
83 
TearDownTestCase()84 void BacktraceUtilsTest::TearDownTestCase()
85 {
86     // check memory/fd/maps
87     CheckResourceUsage(fdCountTotal, mapsCountTotal, memCountTotal);
88 }
89 
SetUp()90 void BacktraceUtilsTest::SetUp()
91 {
92     // get memory/fd/maps
93     fdCount = GetSelfFdCount();
94     mapsCount = GetSelfMapsCount();
95     memCount = GetSelfMemoryCount();
96 }
97 
TearDown()98 void BacktraceUtilsTest::TearDown()
99 {
100 #ifdef USE_JEMALLOC_DFX_INTF
101     mallopt(M_FLUSH_THREAD_CACHE, 0);
102 #endif
103     // check memory/fd/maps
104     CheckResourceUsage(fdCount, mapsCount, memCount);
105 }
106 
CheckBacktraceContent(const std::string & content,bool fast=false)107 static bool CheckBacktraceContent(const std::string& content, bool fast = false)
108 {
109     std::string existKeyWords[] = { "#09", "backtrace_utils_test", "system" };
110     std::string notExistkeyWords[] = {
111 #if defined(__aarch64__)
112         "0000000000000000"
113 #elif defined(__arm__)
114         "00000000"
115 #endif
116     };
117 
118     if (!fast) {
119         for (std::string keyWord : existKeyWords) {
120             if (!CheckContent(content, keyWord, true)) {
121                 return false;
122             }
123         }
124     }
125     for (std::string keyWord : notExistkeyWords) {
126         if (!CheckContent(content, keyWord, false)) {
127             return false;
128         }
129     }
130     return true;
131 }
132 
TestGetBacktraceInterface()133 static bool TestGetBacktraceInterface()
134 {
135     std::string content;
136     if (!GetBacktrace(content)) {
137         return false;
138     }
139 
140     GTEST_LOG_(INFO) << content;
141     if (content.empty()) {
142         return false;
143     }
144 
145     if (!CheckBacktraceContent(content)) {
146         return false;
147     }
148     return true;
149 }
150 
TestGetBacktraceFastInterface()151 static bool TestGetBacktraceFastInterface()
152 {
153 #ifdef __aarch64__
154     std::string content;
155     if (!GetBacktrace(content, true)) {
156         return false;
157     }
158 
159     GTEST_LOG_(INFO) << content;
160     if (content.empty()) {
161         return false;
162     }
163 
164     if (!CheckBacktraceContent(content, true)) {
165         return false;
166     }
167 #endif
168     return true;
169 }
170 
171 /**
172  * @tc.name: BacktraceUtilsTest001
173  * @tc.desc: test log backtrace to hilog, stdout and file
174  * @tc.type: FUNC
175  */
176 HWTEST_F(BacktraceUtilsTest, BacktraceUtilsTest001, TestSize.Level2)
177 {
178     GTEST_LOG_(INFO) << "BacktraceUtilsTest001: start.";
179     ASSERT_EQ(true, PrintBacktrace(STDIN_FILENO));
180     ASSERT_EQ(true, PrintBacktrace(STDOUT_FILENO));
181     ASSERT_EQ(true, PrintBacktrace(STDERR_FILENO));
182     ASSERT_EQ(true, PrintBacktrace());
183     int fd = open(TEST_TEMP_FILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
184     if (fd < 0) {
185         FAIL();
186         return;
187     }
188     ASSERT_EQ(true, PrintBacktrace(fd));
189     close(fd);
190     std::string content;
191     if (!OHOS::HiviewDFX::LoadStringFromFile(TEST_TEMP_FILE, content)) {
192         FAIL();
193     }
194 
195     ASSERT_EQ(CheckBacktraceContent(content), true);
196     GTEST_LOG_(INFO) << "BacktraceUtilsTest001: end.";
197 }
198 
199 /**
200  * @tc.name: BacktraceUtilsTest002
201  * @tc.desc: test get backtrace
202  * @tc.type: FUNC
203  */
204 HWTEST_F(BacktraceUtilsTest, BacktraceUtilsTest002, TestSize.Level2)
205 {
206     GTEST_LOG_(INFO) << "BacktraceUtilsTest002: start.";
207     ASSERT_EQ(TestGetBacktraceInterface(), true);
208     ASSERT_EQ(TestGetBacktraceFastInterface(), true);
209     GTEST_LOG_(INFO) << "BacktraceUtilsTest002: end.";
210 }
211 
212 /**
213  * @tc.name: BacktraceUtilsTest003
214  * @tc.desc: test get backtrace 100 times
215  * @tc.type: FUNC
216  */
217 HWTEST_F(BacktraceUtilsTest, BacktraceUtilsTest003, TestSize.Level2)
218 {
219     GTEST_LOG_(INFO) << "BacktraceUtilsTest003: start.";
220     int32_t loopCount = 100;
221     for (int32_t i = 0; i < loopCount; i++) {
222         ASSERT_EQ(TestGetBacktraceInterface(), true);
223     }
224     GTEST_LOG_(INFO) << "BacktraceUtilsTest003: end.";
225 }
226 
DoCheckBacktraceInMultiThread()227 void DoCheckBacktraceInMultiThread()
228 {
229     std::string content;
230     ASSERT_TRUE(GetBacktrace(content));
231     ASSERT_FALSE(content.empty());
232 }
233 
234 /**
235  * @tc.name: BacktraceUtilsTest004
236  * @tc.desc: test get backtrace in multi-thread situation
237  * @tc.type: FUNC
238  */
239 HWTEST_F(BacktraceUtilsTest, BacktraceUtilsTest004, TestSize.Level2)
240 {
241     GTEST_LOG_(INFO) << "BacktraceUtilsTest004: start.";
242     constexpr int32_t threadCount = 50;
243     std::vector<std::thread> threads(threadCount);
244     for (auto it = std::begin(threads); it != std::end(threads); ++it) {
245         *it = std::thread(DoCheckBacktraceInMultiThread);
246     }
247 
248     for (auto&& thread : threads) {
249         thread.join();
250     }
251     GTEST_LOG_(INFO) << "BacktraceUtilsTest004: end.";
252 }
253 
254 /**
255  * @tc.name: BacktraceUtilsTest005
256  * @tc.desc: test PrintTrace to hilog, stdout and file
257  * @tc.type: FUNC
258  */
259 HWTEST_F(BacktraceUtilsTest, BacktraceUtilsTest005, TestSize.Level2)
260 {
261     GTEST_LOG_(INFO) << "BacktraceUtilsTest005: start.";
262     ASSERT_EQ(true, PrintTrace(STDIN_FILENO));
263     ASSERT_EQ(true, PrintTrace(STDOUT_FILENO));
264     ASSERT_EQ(true, PrintTrace(STDERR_FILENO));
265     ASSERT_EQ(true, PrintTrace());
266     int fd = open(TEST_TEMP_FILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
267     if (fd < 0) {
268         FAIL();
269         return;
270     }
271     ASSERT_EQ(true, PrintTrace(fd));
272     close(fd);
273     std::string content;
274     if (!OHOS::HiviewDFX::LoadStringFromFile(TEST_TEMP_FILE, content)) {
275         FAIL();
276     }
277 
278     ASSERT_EQ(CheckBacktraceContent(content), true);
279     GTEST_LOG_(INFO) << "BacktraceUtilsTest005: end.";
280 }
281 } // namespace HiviewDFX
282 } // namepsace OHOS
283