• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 <sys/wait.h>
27 #include <unistd.h>
28 
29 #include "file_util.h"
30 #include <libunwind_i-ohos.h>
31 #include <libunwind.h>
32 #include <securec.h>
33 
34 #include "dfx_frame_format.h"
35 #include "backtrace_local.h"
36 #include "backtrace_local_context.h"
37 #include "backtrace_local_thread.h"
38 #include "dfx_symbols.h"
39 #include "elapsed_time.h"
40 #include "dfx_test_util.h"
41 
42 using namespace testing;
43 using namespace testing::ext;
44 
45 namespace OHOS {
46 namespace HiviewDFX {
47 #undef LOG_DOMAIN
48 #undef LOG_TAG
49 #define LOG_TAG "BacktraceLocalTest"
50 #define LOG_DOMAIN 0xD002D11
51 namespace {
CheckResourceUsage(uint32_t fdCount,uint32_t mapsCount,uint64_t memCount)52 static void CheckResourceUsage(uint32_t fdCount, uint32_t mapsCount, uint64_t memCount)
53 {
54     // check memory/fd/maps
55     auto curFdCount = GetSelfFdCount();
56     constexpr uint32_t extraVal = 10;
57     GTEST_LOG_(INFO) << "AfterTest Fd New:" << std::to_string(curFdCount);
58     GTEST_LOG_(INFO) << "Fd Old:" << std::to_string(fdCount) << "\n";
59 
60     auto curMapsCount = GetSelfMapsCount();
61     GTEST_LOG_(INFO) << "AfterTest Maps New:" << std::to_string(curMapsCount);
62     GTEST_LOG_(INFO) << "Maps Old:" << std::to_string(mapsCount) << "\n";
63 
64     auto curMemSize = GetSelfMemoryCount();
65     constexpr double ratio = 1.5;
66     GTEST_LOG_(INFO) << "AfterTest Memory New(KB):" << std::to_string(curMemSize);
67     GTEST_LOG_(INFO) << "Memory Old(KB):" << std::to_string(memCount) << "\n";
68 }
69 }
70 class BacktraceLocalTest : public testing::Test {
71 public:
72     static void SetUpTestCase();
73     static void TearDownTestCase();
74     void SetUp();
75     void TearDown();
76 
77     uint32_t fdCount;
78     uint32_t mapsCount;
79     uint64_t memCount;
80 
81     static uint32_t fdCountTotal;
82     static uint32_t mapsCountTotal;
83     static uint64_t memCountTotal;
84 };
85 
86 uint32_t BacktraceLocalTest::fdCountTotal = 0;
87 uint32_t BacktraceLocalTest::mapsCountTotal = 0;
88 uint64_t BacktraceLocalTest::memCountTotal = 0;
89 
SetUpTestCase()90 void BacktraceLocalTest::SetUpTestCase()
91 {
92     BacktraceLocalTest::fdCountTotal = GetSelfFdCount();
93     BacktraceLocalTest::mapsCountTotal = GetSelfMapsCount();
94     BacktraceLocalTest::memCountTotal = GetSelfMemoryCount();
95 }
96 
TearDownTestCase()97 void BacktraceLocalTest::TearDownTestCase()
98 {
99     CheckResourceUsage(fdCountTotal, mapsCountTotal, memCountTotal);
100 }
101 
SetUp()102 void BacktraceLocalTest::SetUp()
103 {
104     fdCount = GetSelfFdCount();
105     mapsCount = GetSelfMapsCount();
106     memCount = GetSelfMemoryCount();
107 }
108 
TearDown()109 void BacktraceLocalTest::TearDown()
110 {
111     CheckResourceUsage(fdCount, mapsCount, memCount);
112 }
113 
114 /**
115  * @tc.name: BacktraceLocalTest001
116  * @tc.desc: test get backtrace of current thread
117  * @tc.type: FUNC
118  */
119 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest001, TestSize.Level2)
120 {
121     GTEST_LOG_(INFO) << "BacktraceLocalTest001: start.";
122     unw_addr_space_t as;
123     unw_init_local_address_space(&as);
124     if (as == nullptr) {
125         FAIL() << "Failed to init address space.\n";
126         return;
127     }
128 
129     auto symbol = std::make_shared<DfxSymbols>();
130     ElapsedTime counter;
131     BacktraceLocalThread thread(BACKTRACE_CURRENT_THREAD);
132     ASSERT_EQ(true, thread.Unwind(as, symbol, 0));
133 
134     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
135     const auto& frames = thread.GetFrames();
136     ASSERT_GT(frames.size(), 0);
137     for (const auto& frame : frames) {
138         GTEST_LOG_(INFO) << DfxFrameFormat::GetFrameStr(frame);
139     }
140 
141     unw_destroy_local_address_space(as);
142     GTEST_LOG_(INFO) << "BacktraceLocalTest001: end.";
143 }
144 
145 int32_t g_tid = 0;
146 std::mutex g_mutex;
Test002()147 __attribute__((noinline)) void Test002()
148 {
149     printf("Test002\n");
150     g_mutex.lock();
151     g_mutex.unlock();
152 }
153 
Test001()154 __attribute__((noinline)) void Test001()
155 {
156     g_tid = gettid();
157     printf("Test001:%d\n", g_tid);
158     Test002();
159 }
160 
161 /**
162  * @tc.name: BacktraceLocalTest003
163  * @tc.desc: test get backtrace of a child thread
164  * @tc.type: FUNC
165  */
166 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest003, TestSize.Level2)
167 {
168     GTEST_LOG_(INFO) << "BacktraceLocalTest003: start.";
169     unw_addr_space_t as;
170     unw_init_local_address_space(&as);
171     if (as == nullptr) {
172         FAIL() << "Failed to init address space.\n";
173         return;
174     }
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     auto symbol = std::make_shared<DfxSymbols>();
183     ElapsedTime counter;
184     BacktraceLocalThread thread(g_tid);
185     ASSERT_EQ(true, thread.Unwind(as, symbol, 0));
186     GTEST_LOG_(INFO) << "UnwindCurrentCost:" << counter.Elapsed();
187     BacktraceLocalContext::GetInstance().CleanUp();
188     const auto& frames = thread.GetFrames();
189     ASSERT_GT(frames.size(), 0);
190     auto backtraceStr = thread.GetFormatedStr(false);
191     ASSERT_GT(backtraceStr.size(), 0);
192     GTEST_LOG_(INFO) << backtraceStr;
193     g_mutex.unlock();
194     unw_destroy_local_address_space(as);
195     g_tid = 0;
196     if (backtraceThread.joinable()) {
197         backtraceThread.join();
198     }
199     GTEST_LOG_(INFO) << "BacktraceLocalTest003: end.";
200 }
201 
202 using GetMap = void (*)(void);
203 /**
204  * @tc.name: BacktraceLocalTest004
205  * @tc.desc: test whether crash log is generated if we call a dlsym func after dlclose
206  * @tc.type: FUNC
207  */
208 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest004, TestSize.Level2)
209 {
210     GTEST_LOG_(INFO) << "BacktraceLocalTest004: start.";
211     pid_t childPid = fork();
212     if (childPid == 0) {
213         void* handle = dlopen("libunwind.z.so", RTLD_LAZY);
214         if (handle == nullptr) {
215             FAIL();
216         }
217 
218         auto getMap = reinterpret_cast<GetMap>(dlsym(handle, "unw_get_map"));
219         if (getMap == nullptr) {
220             dlclose(handle);
221             FAIL();
222         }
223         // close before call functrion
224         dlclose(handle);
225         getMap();
226         _exit(0);
227     }
228 
229     int status;
230     int ret = wait(&status);
231     sleep(1);
232     std::string path = GetCppCrashFileName(childPid);
233     if (path.empty()) {
234         FAIL();
235     }
236     GTEST_LOG_(INFO) << "LogFile: " << path;
237 
238     std::string content;
239     if (!OHOS::HiviewDFX::LoadStringFromFile(path, content)) {
240         FAIL();
241     }
242 
243     // both dlclose debug enabled and disabled cases
244     if (content.find("Not mapped pc") == std::string::npos &&
245         content.find("libunwind") == std::string::npos) {
246         FAIL();
247     }
248 
249     GTEST_LOG_(INFO) << "BacktraceLocalTest004: end.";
250 }
251 
252 /**
253  * @tc.name: BacktraceLocalTest005
254  * @tc.desc: test get backtrace of current process
255  * @tc.type: FUNC
256  */
257 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest005, TestSize.Level2)
258 {
259     GTEST_LOG_(INFO) << "BacktraceLocalTest005: start.";
260     g_mutex.lock();
261     std::thread backtraceThread(Test001);
262     sleep(1);
263     if (g_tid <= 0) {
264         FAIL() << "Failed to create child thread.\n";
265     }
266 
267     std::string stacktrace = GetProcessStacktrace();
268     ASSERT_GT(stacktrace.size(), 0);
269     GTEST_LOG_(INFO) << stacktrace;
270 
271     if (stacktrace.find("backtrace_local_test") == std::string::npos) {
272         FAIL() << "Failed to find pid key word.\n";
273     }
274 
275     g_mutex.unlock();
276     g_tid = 0;
277     if (backtraceThread.joinable()) {
278         backtraceThread.join();
279     }
280     GTEST_LOG_(INFO) << "BacktraceLocalTest005: end.";
281 }
282 
283 /**
284  * @tc.name: BacktraceLocalTest006
285  * @tc.desc: test GetTrace C interface
286  * @tc.type: FUNC
287  */
288 HWTEST_F(BacktraceLocalTest, BacktraceLocalTest006, TestSize.Level2)
289 {
290     GTEST_LOG_(INFO) << "BacktraceLocalTest006: start.";
291     const char* trace = GetTrace();
292     std::string stacktrace(trace);
293     GTEST_LOG_(INFO) << stacktrace;
294     ASSERT_TRUE(stacktrace.find("#00") != std::string::npos);
295     ASSERT_TRUE(stacktrace.find("pc") != std::string::npos);
296     ASSERT_TRUE(stacktrace.find("backtrace_local_test") != std::string::npos);
297     GTEST_LOG_(INFO) << "BacktraceLocalTest006: end.";
298 }
299 } // namespace HiviewDFX
300 } // namepsace OHOS
301