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