1 /* 2 * Copyright (c) 2023 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 <hilog/log.h> 20 #include <malloc.h> 21 #include <map> 22 #include <securec.h> 23 #include <thread> 24 #include <unistd.h> 25 26 #include "dfx_config.h" 27 #include "dfx_frame_formatter.h" 28 #include "dfx_ptrace.h" 29 #include "dfx_regs_get.h" 30 #include "dfx_test_util.h" 31 #include "elapsed_time.h" 32 #include "unwinder.h" 33 34 using namespace testing; 35 using namespace testing::ext; 36 37 namespace OHOS { 38 namespace HiviewDFX { 39 #undef LOG_DOMAIN 40 #undef LOG_TAG 41 #define LOG_TAG "DfxUnwinderTest" 42 #define LOG_DOMAIN 0xD002D11 43 #define TIME_SLEEP 3 44 45 class UnwinderTest : public testing::Test { 46 public: SetUpTestCase()47 static void SetUpTestCase() {} TearDownTestCase()48 static void TearDownTestCase() {} SetUp()49 void SetUp() {} TearDown()50 void TearDown() {} 51 52 std::map<int, std::shared_ptr<Unwinder>> unwinders_; 53 }; 54 55 /** 56 * @tc.name: GetStackRangeTest001 57 * @tc.desc: test unwinder GetStackRange interface in pid == tid 58 * @tc.type: FUNC 59 */ 60 HWTEST_F(UnwinderTest, GetStackRangeTest001, TestSize.Level2) 61 { 62 GTEST_LOG_(INFO) << "GetStackRangeTest001: start."; 63 auto unwinder = std::make_shared<Unwinder>(); 64 uintptr_t stackBottom = 1; 65 uintptr_t stackTop = static_cast<uintptr_t>(-1); 66 GTEST_LOG_(INFO) << "when pid == tid and maps_ != null, GetStackRange(stackBottom, stackTop) is true"; 67 ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop)); 68 // When the param is less than -1, maps_ = null when method Unwinder is constructed 69 auto unwinderNegative = std::make_shared<Unwinder>(-2); 70 GTEST_LOG_(INFO) << "when pid == tid and maps_ == null, GetStackRange(stackBottom, stackTop) is false"; 71 ASSERT_FALSE(unwinderNegative->GetStackRange(stackBottom, stackTop)); 72 GTEST_LOG_(INFO) << "GetStackRangeTest001: end."; 73 } 74 75 /** 76 * @tc.name: GetStackRangeTest002 77 * @tc.desc: test unwinder GetStackRange interface in pid != tid 78 * @tc.type: FUNC 79 */ 80 HWTEST_F(UnwinderTest, GetStackRangeTest002, TestSize.Level2) 81 { 82 GTEST_LOG_(INFO) << "GetStackRangeTest002: start."; 83 auto unwinder = std::make_shared<Unwinder>(); 84 uintptr_t stackBottom = 1; 85 uintptr_t stackTop = static_cast<uintptr_t>(-1); 86 bool result = false; 87 GTEST_LOG_(INFO) << "Run the function with thread will get pid != tid, " 88 "GetStackRange(stackBottom, stackTop) is true"; __anon77cca69e0102null89 std::thread* thread = new std::thread([&]{result = unwinder->GetStackRange(stackBottom, stackTop);}); 90 thread->join(); 91 ASSERT_TRUE(result); 92 GTEST_LOG_(INFO) << "GetStackRangeTest002: end."; 93 } 94 95 /** 96 * @tc.name: UnwinderLocalTest001 97 * @tc.desc: test unwinder local unwind 98 * @tc.type: FUNC 99 */ 100 HWTEST_F(UnwinderTest, UnwinderLocalTest001, TestSize.Level2) 101 { 102 GTEST_LOG_(INFO) << "UnwinderLocalTest001: start."; 103 auto unwinder = std::make_shared<Unwinder>(); 104 ElapsedTime counter; 105 MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal(); 106 time_t elapsed1 = counter.Elapsed(); 107 EXPECT_EQ(true, unwRet) << "UnwinderLocalTest001: Unwind:" << unwRet; 108 auto frames = unwinder->GetFrames(); 109 ASSERT_GT(frames.size(), 1); 110 time_t elapsed2 = counter.Elapsed(); 111 GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2; 112 GTEST_LOG_(INFO) << "UnwinderLocalTest001: frames:\n" << Unwinder::GetFramesStr(frames); 113 GTEST_LOG_(INFO) << "UnwinderLocalTest001: end."; 114 } 115 116 /** 117 * @tc.name: UnwinderLocalTest002 118 * @tc.desc: test unwinder local unwind n counts 119 * @tc.type: FUNC 120 */ 121 HWTEST_F(UnwinderTest, UnwinderLocalTest002, TestSize.Level2) 122 { 123 GTEST_LOG_(INFO) << "UnwinderLocalTest002: start."; 124 unwinders_.clear(); 125 std::shared_ptr<Unwinder> unwinder = nullptr; 126 pid_t pid = getpid(); 127 GTEST_LOG_(INFO) << "pid: " << pid; 128 for (int i = 0; i < 10; ++i) { 129 auto it = unwinders_.find(pid); 130 if (it != unwinders_.end()) { 131 unwinder = it->second; 132 } else { 133 unwinder = std::make_shared<Unwinder>(); 134 } 135 ElapsedTime counter; 136 MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal(); 137 time_t elapsed1 = counter.Elapsed(); 138 EXPECT_EQ(true, unwRet) << "UnwinderLocalTest002: Unwind:" << unwRet; 139 auto frames = unwinder->GetFrames(); 140 ASSERT_GT(frames.size(), 1); 141 time_t elapsed2 = counter.Elapsed(); 142 GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2; 143 GTEST_LOG_(INFO) << "UnwinderLocalTest002: frames:\n" << Unwinder::GetFramesStr(frames); 144 unwinders_[pid] = unwinder; 145 sleep(1); 146 }; 147 GTEST_LOG_(INFO) << "UnwinderLocalTest002: end."; 148 } 149 150 /** 151 * @tc.name: UnwinderLocalTest003 152 * @tc.desc: test unwinder UnwinderLocal interface GetStackRange == false or GetStackRange == true 153 * @tc.type: FUNC 154 */ 155 HWTEST_F(UnwinderTest, UnwinderLocalTest003, TestSize.Level2) 156 { 157 GTEST_LOG_(INFO) << "UnwinderLocalTest003: start."; 158 // When the param is less than -1, maps_ = null when method Unwinder is constructed 159 auto unwinderNegative = std::make_shared<Unwinder>(-2); 160 GTEST_LOG_(INFO) << "when pid == tid and maps_ == null, " 161 "UnwindLocal(maxFrameNum, skipFrameNum) is false"; 162 ASSERT_FALSE(unwinderNegative->UnwindLocal()); 163 auto unwinder = std::make_shared<Unwinder>(); 164 GTEST_LOG_(INFO) << "when pid == tid and maps_ != null, " 165 "UnwindLocal(maxFrameNum, skipFrameNum) is true"; 166 ASSERT_TRUE(unwinder->UnwindLocal()); 167 GTEST_LOG_(INFO) << "UnwinderLocalTest003: end."; 168 } 169 170 /** 171 * @tc.name: UnwinderRemoteTest001 172 * @tc.desc: test unwinder remote unwind 173 * @tc.type: FUNC 174 */ 175 HWTEST_F(UnwinderTest, UnwinderRemoteTest001, TestSize.Level2) 176 { 177 GTEST_LOG_(INFO) << "UnwinderRemoteTest001: start."; 178 pid_t child = fork(); 179 if (child == 0) { 180 sleep(TIME_SLEEP); 181 _exit(0); 182 } 183 184 GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid(); 185 auto unwinder = std::make_shared<Unwinder>(child); 186 bool unwRet = DfxPtrace::Attach(child); 187 EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest001: Attach:" << unwRet; 188 ElapsedTime counter; 189 unwRet = unwinder->UnwindRemote(child); 190 time_t elapsed1 = counter.Elapsed(); 191 EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest001: unwRet:" << unwRet; 192 auto frames = unwinder->GetFrames(); 193 ASSERT_GT(frames.size(), 1); 194 time_t elapsed2 = counter.Elapsed(); 195 GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2; 196 GTEST_LOG_(INFO) << "UnwinderRemoteTest001: frames:\n" << Unwinder::GetFramesStr(frames); 197 DfxPtrace::Detach(child); 198 GTEST_LOG_(INFO) << "UnwinderRemoteTest001: end."; 199 } 200 201 /** 202 * @tc.name: UnwinderRemoteTest002 203 * @tc.desc: test unwinder remote unwind n counts 204 * @tc.type: FUNC 205 */ 206 HWTEST_F(UnwinderTest, UnwinderRemoteTest002, TestSize.Level2) 207 { 208 GTEST_LOG_(INFO) << "UnwinderRemoteTest002: start."; 209 pid_t child = fork(); 210 if (child == 0) { 211 sleep(TIME_SLEEP); 212 _exit(0); 213 } 214 215 GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid(); 216 unwinders_.clear(); 217 std::shared_ptr<Unwinder> unwinder = nullptr; 218 bool unwRet = DfxPtrace::Attach(child); 219 EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest002: Attach:" << unwRet; 220 for (int i = 0; i < 10; ++i) { 221 auto it = unwinders_.find(child); 222 if (it != unwinders_.end()) { 223 unwinder = it->second; 224 } else { 225 unwinder = std::make_shared<Unwinder>(child); 226 } 227 ElapsedTime counter; 228 unwRet = unwinder->UnwindRemote(child); 229 time_t elapsed1 = counter.Elapsed(); 230 EXPECT_EQ(true, unwRet) << "UnwinderRemoteTest002: Unwind:" << unwRet; 231 auto frames = unwinder->GetFrames(); 232 ASSERT_GT(frames.size(), 1); 233 time_t elapsed2 = counter.Elapsed(); 234 GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2; 235 GTEST_LOG_(INFO) << "UnwinderRemoteTest002: frames:\n" << Unwinder::GetFramesStr(frames); 236 unwinders_[child] = unwinder; 237 sleep(1); 238 } 239 DfxPtrace::Detach(child); 240 GTEST_LOG_(INFO) << "UnwinderRemoteTest002: end."; 241 } 242 243 /** 244 * @tc.name: UnwinderRemoteTest003 245 * @tc.desc: test unwinder UnwinderRemote interface GetStackRange == false or GetStackRange == true 246 * @tc.type: FUNC 247 */ 248 HWTEST_F(UnwinderTest, UnwinderRemoteTest003, TestSize.Level2) 249 { 250 GTEST_LOG_(INFO) << "UnwinderRemoteTest003: start."; 251 // When the param is less than -1, pid_ < 0 when method Unwinder is constructed 252 auto unwinderNegative = std::make_shared<Unwinder>(-2); 253 size_t maxFrameNum = 64; 254 size_t skipFrameNum = 0; 255 GTEST_LOG_(INFO) << "when pid <= 0, UnwindLocal(maxFrameNum, skipFrameNum) is false"; 256 ASSERT_FALSE(unwinderNegative->UnwindRemote(-2, maxFrameNum, skipFrameNum)); 257 GTEST_LOG_(INFO) << "UnwinderRemoteTest003: end."; 258 } 259 260 /** 261 * @tc.name: UnwindTest001 262 * @tc.desc: test unwinder unwind interface in remote case 263 * @tc.type: FUNC 264 */ 265 HWTEST_F(UnwinderTest, UnwindTest001, TestSize.Level2) 266 { 267 GTEST_LOG_(INFO) << "UnwindTest001: start."; 268 pid_t child = fork(); 269 if (child == 0) { 270 sleep(TIME_SLEEP); 271 _exit(0); 272 } 273 274 GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid(); 275 auto unwinder = std::make_shared<Unwinder>(child); 276 bool unwRet = DfxPtrace::Attach(child); 277 EXPECT_EQ(true, unwRet) << "UnwindTest001: Attach:" << unwRet; 278 auto regs = DfxRegs::CreateRemoteRegs(child); 279 unwinder->SetRegs(regs); 280 UnwindContext context; 281 context.pid = child; 282 context.regs = regs; 283 ElapsedTime counter; 284 unwRet = unwinder->Unwind(&context); 285 time_t elapsed1 = counter.Elapsed(); 286 EXPECT_EQ(true, unwRet) << "UnwindTest001: Unwind:" << unwRet; 287 auto frames = unwinder->GetFrames(); 288 ASSERT_GT(frames.size(), 1); 289 time_t elapsed2 = counter.Elapsed(); 290 GTEST_LOG_(INFO) << "Elapsed-: " << elapsed1 << "\tElapsed+: " << elapsed2; 291 GTEST_LOG_(INFO) << "UnwindTest001: frames:\n" << Unwinder::GetFramesStr(frames); 292 DfxPtrace::Detach(child); 293 GTEST_LOG_(INFO) << "UnwindTest001: end."; 294 } 295 296 /** 297 * @tc.name: UnwindTest002 298 * @tc.desc: test unwinder unwind interface in local case 299 * @tc.type: FUNC 300 */ 301 HWTEST_F(UnwinderTest, UnwindTest002, TestSize.Level2) 302 { 303 GTEST_LOG_(INFO) << "UnwindTest002: start."; 304 auto unwinder = std::make_shared<Unwinder>(); 305 uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1); 306 ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop)); 307 GTEST_LOG_(INFO) << "UnwindTest002: GetStackRange."; 308 UnwindContext context; 309 context.stackCheck = false; 310 context.stackBottom = stackBottom; 311 context.stackTop = stackTop; 312 313 auto regs = DfxRegs::Create(); 314 auto regsData = regs->RawData(); 315 GetLocalRegs(regsData); 316 unwinder->SetRegs(regs); 317 context.pid = UNWIND_TYPE_LOCAL; 318 context.regs = regs; 319 bool unwRet = unwinder->Unwind(&context); 320 EXPECT_EQ(true, unwRet) << "UnwindTest002: unwRet:" << unwRet; 321 auto frames = unwinder->GetFrames(); 322 ASSERT_GT(frames.size(), 1); 323 GTEST_LOG_(INFO) << "UnwindTest002:frames:\n" << Unwinder::GetFramesStr(frames); 324 GTEST_LOG_(INFO) << "UnwindTest002: end."; 325 } 326 327 /** 328 * @tc.name: UnwindTest003 329 * @tc.desc: test GetPcs GetLastErrorCode GetLastErrorAddr GetFramesByPcs functions 330 * in local case 331 * @tc.type: FUNC 332 */ 333 HWTEST_F(UnwinderTest, UnwindTest003, TestSize.Level2) 334 { 335 GTEST_LOG_(INFO) << "UnwindTest003: start."; 336 337 auto unwinder = std::make_shared<Unwinder>(); 338 MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal(); 339 EXPECT_EQ(true, unwRet) << "UnwindTest003: Unwind ret:" << unwRet; 340 auto pcs = unwinder->GetPcs(); 341 ASSERT_GT(pcs.size(), 0); 342 GTEST_LOG_(INFO) << "pcs.size() > 0\n"; 343 344 uint16_t errorCode = unwinder->GetLastErrorCode(); 345 uint64_t errorAddr = unwinder->GetLastErrorAddr(); 346 GTEST_LOG_(INFO) << "errorCode:" << errorCode; 347 GTEST_LOG_(INFO) << "errorAddr:" << errorAddr; 348 349 std::vector<DfxFrame> frames; 350 std::shared_ptr<DfxMaps> maps = unwinder->GetMaps(); 351 unwinder->GetFramesByPcs(frames, pcs, maps); 352 ASSERT_GT(frames.size(), 1); 353 GTEST_LOG_(INFO) << "UnwindTest003: frames:\n" << Unwinder::GetFramesStr(frames); 354 GTEST_LOG_(INFO) << "UnwindTest003: end."; 355 } 356 357 /** 358 * @tc.name: UnwindTest004 359 * @tc.desc: test unwinder local unwind for 360 * GetFramesStr(const std::vector<std::shared_ptr<DfxFrame>>& frames) 361 * @tc.type: FUNC 362 */ 363 HWTEST_F(UnwinderTest, UnwindTest004, TestSize.Level2) 364 { 365 GTEST_LOG_(INFO) << "UnwindTest004: start."; 366 367 auto unwinder = std::make_shared<Unwinder>(); 368 ElapsedTime counter; 369 MAYBE_UNUSED bool unwRet = unwinder->UnwindLocal(); 370 ASSERT_EQ(true, unwRet) << "UnwindTest004: Unwind:" << unwRet; 371 auto frames = unwinder->GetFrames(); 372 ASSERT_GT(frames.size(), 1); 373 374 auto framesVec = DfxFrameFormatter::ConvertFrames(frames); 375 std::string framesStr = DfxFrameFormatter::GetFramesStr(framesVec); 376 GTEST_LOG_(INFO) << "UnwindTest004: frames:\n" << framesStr; 377 378 string log[] = {"pc", "test_unwind", "#00", "#01", "#02"}; 379 int len = sizeof(log) / sizeof(log[0]); 380 int count = GetKeywordsNum(framesStr, log, len); 381 ASSERT_EQ(count, len) << "UnwindTest004 Failed"; 382 GTEST_LOG_(INFO) << "UnwindTest004: end."; 383 } 384 385 /** 386 * @tc.name: StepTest001 387 * @tc.desc: test unwinder Step interface in remote case 388 * @tc.type: FUNC 389 */ 390 HWTEST_F(UnwinderTest, StepTest001, TestSize.Level2) 391 { 392 GTEST_LOG_(INFO) << "StepTest001: start."; 393 pid_t child = fork(); 394 if (child == 0) { 395 sleep(TIME_SLEEP); 396 _exit(0); 397 } 398 399 GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid(); 400 auto unwinder = std::make_shared<Unwinder>(child); 401 bool unwRet = DfxPtrace::Attach(child); 402 EXPECT_EQ(true, unwRet) << "StepTest001: Attach:" << unwRet; 403 auto regs = DfxRegs::CreateRemoteRegs(child); 404 std::shared_ptr<DfxMaps> maps = DfxMaps::Create(child); 405 unwinder->SetRegs(regs); 406 UnwindContext context; 407 context.pid = child; 408 context.regs = regs; 409 uintptr_t pc, sp; 410 pc = regs->GetPc(); 411 sp = regs->GetSp(); 412 std::shared_ptr<DfxMap> map = nullptr; 413 ASSERT_TRUE(maps->FindMapByAddr(pc, map)); 414 context.map = map; 415 unwRet = unwinder->Step(pc, sp, &context); 416 ASSERT_TRUE(unwRet) << "StepTest001: Unwind:" << unwRet; 417 DfxPtrace::Detach(child); 418 GTEST_LOG_(INFO) << "StepTest001: end."; 419 } 420 421 /** 422 * @tc.name: StepTest002 423 * @tc.desc: test unwinder Step interface in local case 424 * @tc.type: FUNC 425 */ 426 HWTEST_F(UnwinderTest, StepTest002, TestSize.Level2) 427 { 428 GTEST_LOG_(INFO) << "StepTest002: start."; 429 auto unwinder = std::make_shared<Unwinder>(); 430 uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1); 431 ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop)); 432 GTEST_LOG_(INFO) << "StepTest002: GetStackRange."; 433 UnwindContext context; 434 context.pid = UNWIND_TYPE_LOCAL; 435 context.stackCheck = false; 436 context.stackBottom = stackBottom; 437 context.stackTop = stackTop; 438 439 auto regs = DfxRegs::Create(); 440 auto regsData = regs->RawData(); 441 GetLocalRegs(regsData); 442 unwinder->SetRegs(regs); 443 context.regs = regs; 444 445 uintptr_t pc, sp; 446 pc = regs->GetPc(); 447 sp = regs->GetSp(); 448 bool unwRet = unwinder->Step(pc, sp, &context); 449 ASSERT_TRUE(unwRet) << "StepTest002: unwRet:" << unwRet; 450 GTEST_LOG_(INFO) << "StepTest002: end."; 451 } 452 453 #if defined(__aarch64__) 454 /** 455 * @tc.name: StepTest003 456 * @tc.desc: test unwinder FpStep interface in remote case 457 * @tc.type: FUNC 458 */ 459 HWTEST_F(UnwinderTest, StepTest003, TestSize.Level2) 460 { 461 GTEST_LOG_(INFO) << "StepTest003: start."; 462 pid_t child = fork(); 463 if (child == 0) { 464 sleep(TIME_SLEEP); 465 _exit(0); 466 } 467 468 GTEST_LOG_(INFO) << "pid: " << child << ", ppid:" << getpid(); 469 auto unwinder = std::make_shared<Unwinder>(child); 470 bool unwRet = DfxPtrace::Attach(child); 471 EXPECT_EQ(true, unwRet) << "StepTest003: Attach:" << unwRet; 472 auto regs = DfxRegs::CreateRemoteRegs(child); 473 std::shared_ptr<DfxMaps> maps = DfxMaps::Create(child); 474 unwinder->SetRegs(regs); 475 UnwindContext context; 476 context.pid = child; 477 ElapsedTime counter; 478 unwRet = unwinder->UnwindByFp(&context); 479 ASSERT_TRUE(unwRet) << "StepTest003: unwind:" << unwRet; 480 DfxPtrace::Detach(child); 481 time_t elapsed = counter.Elapsed(); 482 GTEST_LOG_(INFO) << "StepTest003: Elapsed: " << elapsed; 483 GTEST_LOG_(INFO) << "StepTest003: end."; 484 } 485 486 /** 487 * @tc.name: StepTest004 488 * @tc.desc: test unwinder FpStep interface in local case 489 * @tc.type: FUNC 490 */ 491 HWTEST_F(UnwinderTest, StepTest004, TestSize.Level2) 492 { 493 GTEST_LOG_(INFO) << "StepTest004: start."; 494 auto unwinder = std::make_shared<Unwinder>(); 495 ElapsedTime counter; 496 uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1); 497 ASSERT_TRUE(unwinder->GetStackRange(stackBottom, stackTop)); 498 GTEST_LOG_(INFO) << "StepTest004: GetStackRange."; 499 500 auto regs = DfxRegs::Create(); 501 auto regsData = regs->RawData(); 502 GetLocalRegs(regsData); 503 UnwindContext context; 504 context.pid = UNWIND_TYPE_LOCAL; 505 context.stackCheck = false; 506 context.stackBottom = stackBottom; 507 context.stackTop = stackTop; 508 unwinder->SetRegs(regs); 509 510 bool unwRet = unwinder->UnwindByFp(&context); 511 ASSERT_TRUE(unwRet) << "StepTest004: unwRet:" << unwRet; 512 size_t unwSize = unwinder->GetPcs().size(); 513 GTEST_LOG_(INFO) << "StepTest004: unwSize: " << unwSize; 514 515 uintptr_t miniRegs[FP_MINI_REGS_SIZE] = {0}; 516 GetFramePointerMiniRegs(miniRegs); 517 regs = DfxRegs::CreateFromRegs(UnwindMode::FRAMEPOINTER_UNWIND, miniRegs); 518 unwinder->SetRegs(regs); 519 size_t idx = 0; 520 uintptr_t pc, fp; 521 while (true) { 522 pc = regs->GetPc(); 523 fp = regs->GetFp(); 524 idx++; 525 if (!unwinder->FpStep(fp, pc, &context) || (pc == 0)) { 526 break; 527 } 528 }; 529 ASSERT_EQ(idx, unwSize) << "StepTest004: idx:" << idx; 530 time_t elapsed = counter.Elapsed(); 531 GTEST_LOG_(INFO) << "StepTest004: Elapsed: " << elapsed; 532 GTEST_LOG_(INFO) << "StepTest004: end."; 533 } 534 #endif 535 536 /** 537 * @tc.name: DfxConfigTest001 538 * @tc.desc: test DfxConfig class functions 539 * @tc.type: FUNC 540 */ 541 HWTEST_F(UnwinderTest, DfxConfigTest001, TestSize.Level2) 542 { 543 GTEST_LOG_(INFO) << "DfxConfigTest001: start."; 544 ASSERT_EQ(DfxConfig::GetConfig().logPersist, false); 545 ASSERT_EQ(DfxConfig::GetConfig().displayRegister, true); 546 ASSERT_EQ(DfxConfig::GetConfig().displayBacktrace, true); 547 ASSERT_EQ(DfxConfig::GetConfig().displayMaps, true); 548 ASSERT_EQ(DfxConfig::GetConfig().displayFaultStack, true); 549 ASSERT_EQ(DfxConfig::GetConfig().dumpOtherThreads, true); 550 ASSERT_EQ(DfxConfig::GetConfig().highAddressStep, 512); 551 ASSERT_EQ(DfxConfig::GetConfig().lowAddressStep, 16); 552 ASSERT_EQ(DfxConfig::GetConfig().maxFrameNums, 256); 553 GTEST_LOG_(INFO) << "DfxConfigTest001: end."; 554 } 555 556 /** 557 * @tc.name: FillFrameTest001 558 * @tc.desc: test unwinder FillFrame interface 559 * in local case 560 * @tc.type: FUNC 561 */ 562 HWTEST_F(UnwinderTest, FillFrameTest001, TestSize.Level2) 563 { 564 GTEST_LOG_(INFO) << "FillFrameTest001: start."; 565 auto unwinder = std::make_shared<Unwinder>(); 566 DfxFrame frame; 567 unwinder->FillFrame(frame); 568 GTEST_LOG_(INFO) << " when DfxFrame::map is null, frame.buildId.size() is 0"; 569 ASSERT_EQ(frame.buildId.size(), 0); 570 string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so.noexit"; 571 auto map = DfxMap::Create(testMap, sizeof(testMap)); 572 frame.map = map; 573 unwinder->FillFrame(frame); 574 GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file not exist, frame.buildId.size() is 0"; 575 ASSERT_EQ(frame.buildId.size(), 0); 576 #ifdef __arm__ 577 testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so"; 578 #else 579 testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so"; 580 #endif 581 map = DfxMap::Create(testMap, sizeof(testMap)); 582 frame.map = map; 583 unwinder->FillFrame(frame); 584 GTEST_LOG_(INFO) << " when DfxFrame::map is not null and file exist, frame.buildId.size() is bigger than 0"; 585 ASSERT_EQ(frame.buildId.size() == 0, false); 586 GTEST_LOG_(INFO) << "FillFrameTest001: end."; 587 } 588 589 /** 590 * @tc.name: FillFramesTest001 591 * @tc.desc: test unwinder FillFrames interface 592 * in local case 593 * @tc.type: FUNC 594 */ 595 HWTEST_F(UnwinderTest, FillFramesTest001, TestSize.Level2) 596 { 597 GTEST_LOG_(INFO) << "FillFramesTest001: start."; 598 #ifdef __arm__ 599 const string testMap = "f6d83000-f6d84000 r--p 00001000 b3:07 1892 /system/lib/init/libinit_context.z.so"; 600 #else 601 const string testMap = "7f0ab40000-7f0ab41000 r--p 00000000 b3:07 1882 /system/lib64/init/libinit_context.z.so"; 602 #endif 603 auto unwinder = std::make_shared<Unwinder>(); 604 std::vector<DfxFrame> frames; 605 DfxFrame frame; 606 auto map = DfxMap::Create(testMap, sizeof(testMap)); 607 frame.map = map; 608 frames.push_back(frame); 609 ASSERT_EQ(frames[0].buildId.size(), 0); 610 unwinder->FillFrames(frames); 611 ASSERT_EQ(frames[0].buildId.size() == 0, false); 612 GTEST_LOG_(INFO) << "FillFramesTest001: end."; 613 } 614 615 #if defined(__arm__) || defined(__aarch64__) 616 /** 617 * @tc.name: UnwindLocalWithContextTest001 618 * @tc.desc: test unwinder UnwindLocalWithContext interface 619 * in local case 620 * @tc.type: FUNC 621 */ 622 HWTEST_F(UnwinderTest, UnwindLocalWithContextTest001, TestSize.Level2) 623 { 624 GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: start."; 625 auto regs = DfxRegs::Create(); 626 auto regsData = regs->RawData(); 627 GetLocalRegs(regsData); 628 ucontext_t context; 629 (void)memset_s(&context, sizeof(context), 0, sizeof(context)); 630 #ifdef __arm__ 631 context.uc_mcontext.arm_r0 = *(regs->GetReg(REG_ARM_R0)); 632 context.uc_mcontext.arm_r1 = *(regs->GetReg(REG_ARM_R1)); 633 context.uc_mcontext.arm_r2 = *(regs->GetReg(REG_ARM_R2)); 634 context.uc_mcontext.arm_r3 = *(regs->GetReg(REG_ARM_R3)); 635 context.uc_mcontext.arm_r4 = *(regs->GetReg(REG_ARM_R4)); 636 context.uc_mcontext.arm_r5 = *(regs->GetReg(REG_ARM_R5)); 637 context.uc_mcontext.arm_r6 = *(regs->GetReg(REG_ARM_R6)); 638 context.uc_mcontext.arm_r7 = *(regs->GetReg(REG_ARM_R7)); 639 context.uc_mcontext.arm_r8 = *(regs->GetReg(REG_ARM_R8)); 640 context.uc_mcontext.arm_r9 = *(regs->GetReg(REG_ARM_R9)); 641 context.uc_mcontext.arm_r10 = *(regs->GetReg(REG_ARM_R10)); 642 context.uc_mcontext.arm_fp = *(regs->GetReg(REG_ARM_R11)); 643 context.uc_mcontext.arm_ip = *(regs->GetReg(REG_ARM_R12)); 644 context.uc_mcontext.arm_sp = *(regs->GetReg(REG_ARM_R13)); 645 context.uc_mcontext.arm_lr = *(regs->GetReg(REG_ARM_R14)); 646 context.uc_mcontext.arm_pc = *(regs->GetReg(REG_ARM_R15)); 647 #else 648 for (int i = 0; i < REG_LAST; ++i) { 649 context.uc_mcontext.regs[i] = *(regs->GetReg(i)); 650 } 651 #endif 652 auto unwinder = std::make_shared<Unwinder>(); 653 ASSERT_TRUE(unwinder->UnwindLocalWithContext(context)); 654 auto frames = unwinder->GetFrames(); 655 GTEST_LOG_(INFO) << unwinder->GetFramesStr(frames); 656 ASSERT_GT(frames.size(), 1); 657 GTEST_LOG_(INFO) << "UnwindLocalWithContextTest001: end."; 658 } 659 #endif 660 661 /** 662 * @tc.name: GetSymbolByPcTest001 663 * @tc.desc: test unwinder GetSymbolByPc interface 664 * in local case 665 * @tc.type: FUNC 666 */ 667 HWTEST_F(UnwinderTest, GetSymbolByPcTest001, TestSize.Level2) 668 { 669 GTEST_LOG_(INFO) << "GetSymbolByPcTest001: start."; 670 auto unwinder = std::make_shared<Unwinder>(); 671 unwinder->UnwindLocal(); 672 auto pcs = unwinder->GetPcs(); 673 std::string funcName; 674 uint64_t funcOffset; 675 std::shared_ptr<DfxMaps> maps = std::make_shared<DfxMaps>(); 676 ASSERT_FALSE(unwinder->GetSymbolByPc(0x00000000, maps, funcName, funcOffset)); // Find map is null 677 ASSERT_FALSE(unwinder->GetSymbolByPc(pcs[0], maps, funcName, funcOffset)); // Get elf is null 678 GTEST_LOG_(INFO) << "GetSymbolByPcTest001: end."; 679 } 680 } // namespace HiviewDFX 681 } // namepsace OHOS 682 683