1/* 2 * Copyright (c) 2021 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 "callstack_test.h" 17 18using namespace testing::ext; 19using namespace testing; 20using namespace std; 21using namespace OHOS::HiviewDFX; 22namespace OHOS { 23namespace Developtools { 24namespace HiPerf { 25class CallStackTest : public testing::Test { 26public: 27 static void SetUpTestCase(void); 28 static void TearDownTestCase(void); 29 void SetUp(); 30 void TearDown(); 31 default_random_engine rnd_; 32}; 33 34void CallStackTest::SetUpTestCase() 35{ 36 DebugLogger::GetInstance()->Reset(); 37 DebugLogger::GetInstance()->OpenLog(DEFAULT_UT_LOG_DIR + "CallStackTest.txt"); 38} 39 40void CallStackTest::TearDownTestCase() 41{ 42 DebugLogger::GetInstance()->RestoreLog(); 43} 44 45void CallStackTest::SetUp() {} 46 47void CallStackTest::TearDown() {} 48 49/** 50 * @tc.name: ExpandCallStack 51 * @tc.desc: 52 * @tc.type: FUNC 53 */ 54HWTEST_F(CallStackTest, ExpendCallStackEmpty, TestSize.Level1) 55{ 56 /* 57 3 2 1 58 cache A -> B -> C 59 new C 60 expand A -> B -> C 61 */ 62 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 63 CallStack callStack; 64 65 std::vector<DfxFrame> stack1 = { 66 {0x1u, 0x1u}, 67 {0x2u, 0x2u}, 68 {0x3u, 0x3u}, 69 }; 70 std::vector<DfxFrame> stack2 = {}; 71 72 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 73 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u); 74 ASSERT_NE(stack1, stack2); 75} 76 77/** 78 * @tc.name: ExpandCallStack 79 * @tc.desc: 80 * @tc.type: FUNC 81 */ 82HWTEST_F(CallStackTest, ExpendCallStackC, TestSize.Level1) 83{ 84 /* 85 3 2 1 86 cache A -> B -> C 87 new C 88 expand A -> B -> C 89 */ 90 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 91 CallStack callStack; 92 93 std::vector<DfxFrame> stack1 = { 94 {0x1u, 0x1u}, 95 {0x2u, 0x2u}, 96 {0x3u, 0x3u}, 97 }; 98 std::vector<DfxFrame> stack2 = { 99 {0x1u, 0x1u}, 100 }; 101 102 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 103 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 2u); 104 ASSERT_EQ(stack1, stack2); 105} 106 107/** 108 * @tc.name: ExpandCallStack 109 * @tc.desc: 110 * @tc.type: FUNC 111 */ 112HWTEST_F(CallStackTest, ExpendCallStackBC, TestSize.Level1) 113{ 114 /* 115 3 2 1 116 cache A -> B -> C 117 new B -> C 118 expand A -> B -> C 119 */ 120 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 121 CallStack callStack; 122 123 std::vector<DfxFrame> stack1 = { 124 {0x1u, 0x1u}, 125 {0x2u, 0x2u}, 126 {0x3u, 0x3u}, 127 }; 128 std::vector<DfxFrame> stack2 = { 129 {0x1u, 0x1u}, 130 {0x2u, 0x2u}, 131 }; 132 133 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 134 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u); 135 ASSERT_EQ(stack1, stack2); 136} 137 138/** 139 * @tc.name: ExpandCallStack 140 * @tc.desc: 141 * @tc.type: FUNC 142 */ 143HWTEST_F(CallStackTest, ExpendCallStackABC, TestSize.Level1) 144{ 145 /* 146 3 2 1 147 cache A -> B -> C 148 new A -> B -> C 149 expand A -> B -> C 150 */ 151 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 152 CallStack callStack; 153 154 std::vector<DfxFrame> stack1 = { 155 {0x1u, 0x1u}, 156 {0x2u, 0x2u}, 157 {0x3u, 0x3u}, 158 }; 159 std::vector<DfxFrame> stack2 = { 160 {0x1u, 0x1u}, 161 {0x2u, 0x2u}, 162 {0x3u, 0x3u}, 163 }; 164 165 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 166 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u); 167 ASSERT_EQ(stack1, stack2); 168} 169 170/** 171 * @tc.name: ExpandCallStack 172 * @tc.desc: 173 * @tc.type: FUNC 174 */ 175HWTEST_F(CallStackTest, ExpendCallStackAB, TestSize.Level1) 176{ 177 /* 178 3 2 1 179 cache A -> B -> C 180 new A -> B 181 expand A -> B 182 */ 183 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 184 CallStack callStack; 185 186 std::vector<DfxFrame> stack1 = { 187 {0x1u, 0x1u}, 188 {0x2u, 0x2u}, 189 {0x3u, 0x3u}, 190 }; 191 std::vector<DfxFrame> stack2 = { 192 {0x2u, 0x2u}, 193 {0x3u, 0x3u}, 194 }; 195 196 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 197 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u); 198 ASSERT_NE(stack1, stack2); 199} 200 201/** 202 * @tc.name: ExpandCallStack 203 * @tc.desc: 204 * @tc.type: FUNC 205 */ 206HWTEST_F(CallStackTest, ExpendCallStackA, TestSize.Level1) 207{ 208 /* 209 3 2 1 210 cache A -> B -> C 211 new A 212 expand A 213 */ 214 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 215 CallStack callStack; 216 217 std::vector<DfxFrame> stack1 = { 218 {0x1u, 0x1u}, 219 {0x2u, 0x2u}, 220 {0x3u, 0x3u}, 221 }; 222 std::vector<DfxFrame> stack2 = { 223 {0x3u, 0x3u}, 224 }; 225 226 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 227 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 0u); 228 ASSERT_NE(stack1, stack2); 229} 230 231/** 232 * @tc.name: ExpandCallStack 233 * @tc.desc: 234 * @tc.type: FUNC 235 */ 236HWTEST_F(CallStackTest, ExpendCallStackB, TestSize.Level1) 237{ 238 /* 239 3 2 1 240 cache A -> B -> C 241 new B 242 expand A -> B 243 */ 244 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 245 CallStack callStack; 246 247 std::vector<DfxFrame> stack1 = { 248 {0x1u, 0x1u}, 249 {0x2u, 0x2u}, 250 {0x3u, 0x3u}, 251 }; 252 std::vector<DfxFrame> stack2 = { 253 {0x2u, 0x2u}, 254 }; 255 std::vector<DfxFrame> stack3 = { 256 {0x2u, 0x2u}, 257 {0x3u, 0x3u}, 258 }; 259 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 260 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 1u); 261 ASSERT_NE(stack1, stack2); 262 ASSERT_EQ(stack3, stack2); 263} 264 265/** 266 * @tc.name: ExpandCallStack 267 * @tc.desc: 268 * @tc.type: FUNC 269 */ 270HWTEST_F(CallStackTest, ExpendCallStackB2, TestSize.Level1) 271{ 272 /* 273 3 2 1 274 cache A -> B -> C 275 new B 276 expand A -> B 277 */ 278 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 279 CallStack callStack; 280 281 std::vector<DfxFrame> stack1 = { 282 {0x1u, 0x1u}, 283 {0x2u, 0x2u}, 284 {0x3u, 0x3u}, 285 }; 286 std::vector<DfxFrame> stack2 = { 287 {0x2u, 0x2u}, 288 }; 289 std::vector<DfxFrame> stack3 = { 290 {0x2u, 0x2u}, 291 {0x3u, 0x3u}, 292 }; 293 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u); 294 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u); 295 ASSERT_NE(stack1, stack2); 296 ASSERT_NE(stack3, stack2); 297} 298 299/** 300 * @tc.name: ExpandCallStack 301 * @tc.desc: 302 * @tc.type: FUNC 303 */ 304HWTEST_F(CallStackTest, ExpendCallStackB0, TestSize.Level1) 305{ 306 /* 307 3 2 1 308 cache A -> B -> C 309 new B 310 expand A -> B 311 */ 312 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 313 CallStack callStack; 314 315 std::vector<DfxFrame> stack1 = { 316 {0x1u, 0x1u}, 317 {0x2u, 0x2u}, 318 {0x3u, 0x3u}, 319 }; 320 std::vector<DfxFrame> stack2 = { 321 {0x2u, 0x2u}, 322 }; 323 std::vector<DfxFrame> stack3 = { 324 {0x2u, 0x2u}, 325 {0x3u, 0x3u}, 326 }; 327 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 0), 0u); 328 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 0), 0u); 329 ASSERT_NE(stack1, stack2); 330 ASSERT_NE(stack3, stack2); 331} 332 333/** 334 * @tc.name: ExpandCallStack 335 * @tc.desc: 336 * @tc.type: FUNC 337 */ 338HWTEST_F(CallStackTest, ExpendCallStackBC2, TestSize.Level1) 339{ 340 /* 341 3 2 1 342 cache A -> B -> C 343 new B -> C 344 expand A -> B -> C 345 */ 346 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true); 347 CallStack callStack; 348 349 std::vector<DfxFrame> stack1 = { 350 {0x1u, 0x1u}, 351 {0x2u, 0x2u}, 352 {0x3u, 0x3u}, 353 }; 354 std::vector<DfxFrame> stack2 = { 355 {0x1u, 0x1u}, 356 {0x2u, 0x2u}, 357 }; 358 359 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2), 0u); 360 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 1u); 361 ASSERT_EQ(stack1, stack2); 362} 363 364/** 365 * @tc.name: ExpandCallStack 366 * @tc.desc: 367 * @tc.type: FUNC 368 */ 369HWTEST_F(CallStackTest, ExpendCallStackABCDE, TestSize.Level1) 370{ 371 /* 372 0. A -> B -> C -> E -> F 373 1. C -> E -> F 374 2. B -> C 375 3. A -> B -> C 376 4. B -> F -> F 377 */ 378 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 379 CallStack callStack; 380 381 std::vector<DfxFrame> stackFull = { 382 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA}, 383 }; 384 std::vector<DfxFrame> stackBC = { 385 {0xC, 0xC}, 386 {0xB, 0xB}, 387 }; 388 std::vector<DfxFrame> stackABC = { 389 {0xC, 0xC}, 390 {0xB, 0xB}, 391 {0xA, 0xA}, 392 }; 393 std::vector<DfxFrame> stackBFF = { 394 {0xF, 0xF}, 395 {0xF, 0xF}, 396 {0xB, 0xB}, 397 }; 398 std::vector<DfxFrame> stackBFF2 = { 399 {0xF, 0xF}, 400 {0xF, 0xF}, 401 {0xB, 0xB}, 402 }; 403 404 ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u); 405 ASSERT_EQ(callStack.ExpandCallStack(0, stackBC), 1u); 406 ASSERT_EQ(callStack.ExpandCallStack(0, stackABC), 0u); 407 ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF), 1u); 408 409 // use stackBFF 410 ASSERT_EQ(callStack.ExpandCallStack(0, stackBFF2, 2), 1u); 411} 412 413/** 414 * @tc.name: ExpandCallStack 415 * @tc.desc: 416 * @tc.type: FUNC 417 */ 418HWTEST_F(CallStackTest, ExpendCallStackFailure, TestSize.Level1) 419{ 420 /* 421 0. A -> B -> C -> E -> F 422 1. C -> E -> F 423 2. B -> C 424 3. A -> B -> C 425 4. B -> F -> F 426 */ 427 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 428 CallStack callStack; 429 430 std::vector<DfxFrame> stackFull = { 431 {0xC, 0xC}, 432 {0xB, 0xB}, 433 {0xA, 0xA}, 434 }; 435 std::vector<DfxFrame> stackDE = { 436 {0xE, 0xE}, 437 {0xD, 0xD}, 438 }; 439 440 ASSERT_EQ(callStack.ExpandCallStack(0, stackFull), 0u); 441 ASSERT_EQ(callStack.ExpandCallStack(0, stackDE), 0u); 442} 443 444/** 445 * @tc.name: ExpandCallStack 446 * @tc.desc: 447 * @tc.type: FUNC 448 */ 449HWTEST_F(CallStackTest, ExpendCallStackTwoChance, TestSize.Level1) 450{ 451 /* 452 0. A -> B -> C -> E -> F 453 1. 2 -> C -> E -> F 454 2. C 455 */ 456 ScopeDebugLevel tempLogLevel(LEVEL_MUCH); 457 CallStack callStack; 458 459 std::vector<DfxFrame> stack0 = { 460 {0xE, 0xE}, {0xD, 0xD}, {0xC, 0xC}, {0xB, 0xB}, {0xA, 0xA}, 461 }; 462 std::vector<DfxFrame> stack1 = { 463 {0xE, 0xE}, 464 {0xD, 0xD}, 465 {0xC, 0xC}, 466 {0x2, 0x2}, 467 }; 468 std::vector<DfxFrame> stackC = { 469 {0xC, 0xC}, 470 }; 471 std::vector<DfxFrame> stackC2 = { 472 {0xC, 0xC}, 473 {0x2, 0x2}, 474 }; 475 ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u); 476 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 477 ASSERT_EQ(callStack.ExpandCallStack(0, stackC), 1u); 478} 479 480/** 481 * @tc.name: ExpandCallStack 482 * @tc.desc: 483 * @tc.type: FUNC 484 */ 485HWTEST_F(CallStackTest, ExpendCallStackFullCache, TestSize.Level1) 486{ 487 CallStack callStack; 488 for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) { 489 std::vector<DfxFrame> stack = {{rnd_(), rnd_()}}; 490 callStack.ExpandCallStack(0, stack); 491 } 492 for (size_t i = 0; i < MAX_CALL_FRAME_EXPAND_CACHE_SIZE; i++) { 493 std::vector<DfxFrame> stack = {{rnd_(), rnd_()}}; 494 callStack.ExpandCallStack(0, stack); 495 } 496 EXPECT_EQ(callStack.cachedCallFramesMap_[0].size(), MAX_CALL_FRAME_EXPAND_CACHE_SIZE); 497} 498 499/** 500 * @tc.name: ExpandCallStack 501 * @tc.desc: 502 * @tc.type: FUNC 503 */ 504HWTEST_F(CallStackTest, ExpendCallStackSmall, TestSize.Level1) 505{ 506 CallStack callStack; 507 std::vector<DfxFrame> stack0 = {}; 508 std::vector<DfxFrame> stack1 = {{0x1, 0x1}}; 509 std::vector<DfxFrame> stack2 = {{0x1, 0x1}, {0x2, 0x2}}; 510 ASSERT_EQ(callStack.ExpandCallStack(0, stack0), 0u); 511 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 512 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 513 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2), 0u); 514} 515 516/** 517 * @tc.name: ExpandCallStack 518 * @tc.desc: 519 * @tc.type: FUNC 520 */ 521HWTEST_F(CallStackTest, ExpendCallStackLimit, TestSize.Level1) 522{ 523 /* 524 3 2 1 0 525 cache A -> B -> C 526 stack2 C 527 expand C 528 529 stack3 B -> C 530 expand A -> B -> C 531 532 stack4 C -> D 533 expand C 534 */ 535 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true); 536 CallStack callStack; 537 538 std::vector<DfxFrame> stack1 = { 539 {0x1u, 0x1u}, 540 {0x2u, 0x2u}, 541 {0x3u, 0x3u}, 542 }; 543 std::vector<DfxFrame> stack2 = { 544 {0x1u, 0x1u}, 545 }; 546 std::vector<DfxFrame> stack3 = { 547 {0x1u, 0x1u}, 548 {0x2u, 0x2u}, 549 }; 550 std::vector<DfxFrame> stack4 = { 551 {0x0u, 0x0u}, 552 {0x1u, 0x1u}, 553 }; 554 555 ASSERT_EQ(callStack.ExpandCallStack(0, stack1, 2u), 0u); 556 ASSERT_EQ(callStack.ExpandCallStack(0, stack2, 2u), 0u); 557 ASSERT_EQ(callStack.ExpandCallStack(0, stack3, 2u), 1u); 558 EXPECT_THAT(stack1, ContainerEq(stack3)); 559 ASSERT_EQ(callStack.ExpandCallStack(0, stack4, 2u), 0u); 560} 561 562/** 563 * @tc.name: ExpandCallStack 564 * @tc.desc: 565 * @tc.type: FUNC 566 */ 567HWTEST_F(CallStackTest, ExpendCallStackABABAB, TestSize.Level1) 568{ 569 /* 570 Caller Called 571 cache A -> B -> C -> A -> B -> C -> A -> B 572 stack2 C 573 expand A -> B -> C -> A -> B -> C 574 575 stack3 B -> C 576 expand A -> B -> C -> A -> B -> C 577 578 stack4 C -> D 579 expand A -> B -> C -> A -> B -> C -> D 580 */ 581 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true); 582 CallStack callStack; 583 584 std::vector<DfxFrame> stack1 = { 585 {0xb, 0xb}, {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, 586 {0xa, 0xa}, {0xc, 0xc}, {0xb, 0xb}, {0xa, 0xa}, 587 }; 588 std::vector<DfxFrame> stack2 = { 589 {0xc, 0xc}, 590 }; 591 std::vector<DfxFrame> stack3 = { 592 {0xc, 0xc}, 593 {0xb, 0xb}, 594 }; 595 std::vector<DfxFrame> stack4 = { 596 {0xd, 0xd}, 597 {0xc, 0xc}, 598 }; 599 600 ASSERT_EQ(callStack.ExpandCallStack(0, stack1), 0u); 601 ASSERT_EQ(callStack.ExpandCallStack(0, stack2), 5u); 602 ASSERT_EQ(callStack.ExpandCallStack(0, stack3), 4u); 603 ASSERT_EQ(callStack.ExpandCallStack(0, stack4), 5u); 604} 605 606/** 607 * @tc.name: UnwindCallStack 608 * @tc.desc: 609 * @tc.type: FUNC 610 */ 611HWTEST_F(CallStackTest, UnwindCallStack, TestSize.Level1) 612{ 613#if is_linux 614 return; 615#endif 616 617 std::vector<u64> regs; 618 std::vector<u8> data; 619 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_REGS_0, regs); 620 LoadFromFile(PATH_RESOURCE_TEST_DWARF_DATA + TEST_DWARF_USER_DATA_0, data); 621 if (regs.size() > 0 and data.size() > 0) { 622#ifdef __arm__ 623 ASSERT_EQ(regs.size(), 16u); 624#endif 625 std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles; 626 auto &symbolsFile = symbolsFiles.emplace_back(SymbolsFile::CreateSymbolsFile( 627 SYMBOL_ELF_FILE, TEST_DWARF_ELF)); 628 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DWARF_DATA), true); 629 ASSERT_EQ(symbolsFile->LoadSymbols(), true); 630 // fix the name 631 symbolsFile->filePath_ = TEST_DWARF_MMAP.front().fileName; 632 633 VirtualThread thread(getpid(), symbolsFiles); 634 MakeMaps(thread); 635 std::vector<DfxFrame> callFrames; 636 CallStack callStack; 637 638 bool ret = callStack.UnwindCallStack(thread, false, regs.data(), regs.size(), data.data(), data.size(), 639 callFrames); 640 ASSERT_TRUE(ret); 641 ASSERT_LE(TEST_DWARF_FRAMES.size(), callFrames.size()); 642 } 643} 644} // namespace HiPerf 645} // namespace Developtools 646} // namespace OHOS 647