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 <dlfcn.h> 17 #include <fcntl.h> 18 #include <hwext/gtest-ext.h> 19 #include <hwext/gtest-tag.h> 20 #include <vector> 21 #include <sys/syscall.h> 22 23 #include "buffer_splitter.h" 24 #include "logging.h" 25 #include <fstream> 26 #include <iostream> 27 28 #pragma clang optimize off 29 30 using namespace testing::ext; 31 32 namespace { 33 constexpr int DEFAULT_MALLOC_SIZE = 10; 34 constexpr int DEFAULT_CALLOC_SIZE = 100; 35 constexpr int DEFAULT_REALLOC_SIZE = 1000; 36 constexpr int DATA_SIZE = 50; 37 constexpr int WAIT_KILL_SIGNL = 4; 38 constexpr int SLEEP_TIME = 5; 39 constexpr int WAIT_FLUSH = 2; 40 41 const std::string DEFAULT_NATIVE_DAEMON_PATH("/system/bin/native_daemon"); 42 constexpr int SHARE_MEMORY_SIZE = 1000 * 4096; 43 constexpr int BUFFER_SIZE = 100 * 1024; 44 constexpr int DEFAULT_DEPTH = 32; 45 constexpr int CALLOC_DEPTH = 13; 46 constexpr int REALLOC_DEPTH = 10; 47 constexpr int MALLOC_VEC_SIZE = 5; 48 constexpr int FREE_VEC_SIZE = 4; 49 constexpr int MALLOC_GET_DATE_SIZE = 3; 50 constexpr int FREE_GET_DATA_SIZE = 2; 51 std::unique_ptr<uint8_t[]> g_buffer = std::make_unique<uint8_t[]>(BUFFER_SIZE); 52 const std::string DEFAULT_PATH("/data/local/tmp/"); 53 const std::string DEFAULT_LIBA_PATH("/data/local/tmp/liba.z.so"); 54 const std::string DEFAULT_LIBB_PATH("/data/local/tmp/libb.z.so"); 55 const std::string DEFAULT_LIBNATIVETEST_PATH("/data/local/tmp/libnativetest_so.z.so"); 56 const int LIBA_MALLOC_SIZE = 888; 57 const int LIBB_MALLOC_SIZE = 666; 58 typedef char* (*DepthMallocSo)(int depth, int mallocSize); 59 typedef void (*DepthFreeSo)(int depth, char *p); 60 61 using StaticSpace = struct { 62 int data[DATA_SIZE]; 63 } ; 64 65 class CheckHookDataTest : public ::testing::Test { 66 public: SetUpTestCase()67 static void SetUpTestCase() {} TearDownTestCase()68 static void TearDownTestCase() {} 69 StartDaemonProcessArgs()70 void StartDaemonProcessArgs() 71 { 72 outFile_ = DEFAULT_PATH + "hooktest_"+ outFileType_ + mode_[modeIndex_] + ".txt"; 73 int processNum = fork(); 74 if (processNum == 0) { 75 command_.push_back(const_cast<char*>(DEFAULT_NATIVE_DAEMON_PATH.c_str())); 76 command_.push_back(const_cast<char*>("-o")); 77 command_.push_back(const_cast<char*>(outFile_.c_str())); 78 command_.push_back(const_cast<char*>("-s")); 79 command_.push_back(const_cast<char*>(std::to_string(SHARE_MEMORY_SIZE).c_str())); 80 command_.push_back(const_cast<char*>("-p")); 81 command_.push_back(const_cast<char*>(std::to_string(hookPid_).c_str())); 82 command_.push_back(const_cast<char*>("-u")); 83 command_.push_back(const_cast<char*>(mode_[modeIndex_].c_str())); 84 if (unwindDepth_ > 0) { 85 command_.push_back(const_cast<char*>("-d")); 86 command_.push_back(const_cast<char*>(std::to_string(unwindDepth_).c_str())); 87 } 88 if (statisticsInterval_ > 0) { 89 command_.push_back(const_cast<char*>("-S")); 90 command_.push_back(const_cast<char*>(std::to_string(statisticsInterval_).c_str())); 91 } 92 if (offlineSymbolization_) { 93 command_.push_back(const_cast<char*>("-O")); 94 command_.push_back(const_cast<char*>("true")); 95 } 96 if (callframeCompress_) { 97 command_.push_back(const_cast<char*>("-C")); 98 command_.push_back(const_cast<char*>("true")); 99 } 100 if (stringCompress_) { 101 command_.push_back(const_cast<char*>("-c")); 102 command_.push_back(const_cast<char*>("true")); 103 } 104 if (rawString_) { 105 command_.push_back(const_cast<char*>("-r")); 106 command_.push_back(const_cast<char*>("true")); 107 } 108 command_.push_back(nullptr); 109 execv(DEFAULT_NATIVE_DAEMON_PATH.c_str(), command_.data()); 110 _exit(1); 111 } else { 112 daemonPid_ = processNum; 113 } 114 } 115 StringSplit(const std::string & str,char delim=';')116 std::vector<std::string>& StringSplit(const std::string& str, char delim = ';') 117 { 118 std::stringstream ss(str); 119 std::string item; 120 static std::vector<std::string> elems; 121 elems.clear(); 122 while (std::getline(ss, item, delim)) { 123 if (!item.empty()) { 124 elems.push_back(item); 125 } 126 } 127 return elems; 128 } 129 StopProcess(int processNum)130 void StopProcess(int processNum) 131 { 132 std::string stopCmd = "kill -9 " + std::to_string(processNum); 133 system(stopCmd.c_str()); 134 } 135 ReadFile(std::string file)136 int32_t ReadFile(std::string file) 137 { 138 int fd = -1; 139 ssize_t bytesRead = 0; 140 char filePath[PATH_MAX + 1] = {0}; 141 142 if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s", file.c_str()) < 0) { 143 const int bufSize = 256; 144 char buf[bufSize] = { 0 }; 145 strerror_r(errno, buf, bufSize); 146 HILOG_ERROR(LOG_CORE, "snprintf_s(%s) error, errno(%d:%s)", file.c_str(), errno, buf); 147 return -1; 148 } 149 150 char* realPath = realpath(filePath, nullptr); 151 if (realPath == nullptr) { 152 const int bufSize = 256; 153 char buf[bufSize] = { 0 }; 154 strerror_r(errno, buf, bufSize); 155 HILOG_ERROR(LOG_CORE, "realpath(%s) failed, errno(%d:%s)", file.c_str(), errno, buf); 156 return -1; 157 } 158 159 fd = open(realPath, O_RDONLY | O_CLOEXEC); 160 if (fd == -1) { 161 const int bufSize = 256; 162 char buf[bufSize] = { 0 }; 163 strerror_r(errno, buf, bufSize); 164 HILOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, realPath, errno, buf); 165 return -1; 166 } 167 if (g_buffer == nullptr) { 168 HILOG_ERROR(LOG_CORE, "%s:empty address, g_buffer is NULL", __func__); 169 close(fd); 170 return -1; 171 } 172 bytesRead = read(fd, g_buffer.get(), BUFFER_SIZE - 1); 173 if (bytesRead <= 0) { 174 close(fd); 175 HILOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, realPath, errno); 176 return -1; 177 } 178 close(fd); 179 free(realPath); 180 181 return bytesRead; 182 } 183 DepthFree(int depth,void * p)184 void DepthFree(int depth, void *p) 185 { 186 StaticSpace staticeData; 187 if (depth == 0) { 188 staticeData.data[0] = 1; 189 free(p); 190 return; 191 } 192 return (DepthFree(depth - 1, p)); 193 } 194 DepthMalloc(int depth)195 char *DepthMalloc(int depth) 196 { 197 StaticSpace staticeData; 198 if (depth == 0) { 199 staticeData.data[0] = 1; 200 return reinterpret_cast<char *>(malloc(DEFAULT_MALLOC_SIZE)); 201 } 202 return (DepthMalloc(depth - 1)); 203 } 204 ApplyForMalloc(int depth)205 void ApplyForMalloc(int depth) 206 { 207 char *p = DepthMalloc(depth); 208 if (!p) { 209 const int bufSize = 256; 210 char buf[bufSize] = { 0 }; 211 strerror_r(errno, buf, bufSize); 212 HILOG_ERROR(LOG_CORE, "ApplyForMalloc: malloc failure, errno(%d:%s)", errno, buf); 213 return; 214 } 215 DepthFree(depth, p); 216 } 217 DlopenAndCloseSo(std::string filePath,int size,int depth)218 void DlopenAndCloseSo(std::string filePath, int size, int depth) 219 { 220 char *ptr = nullptr; 221 void *handle = nullptr; 222 DepthMallocSo mallocFunc = nullptr; 223 DepthFreeSo freeFunc = nullptr; 224 225 handle = dlopen(filePath.data(), RTLD_LAZY); 226 if (handle == nullptr) { 227 fprintf(stderr, "library not exist!\n"); 228 exit(0); 229 } 230 mallocFunc = (DepthMallocSo)dlsym(handle, "DepthMallocSo"); 231 freeFunc = (DepthFreeSo)dlsym(handle, "DepthFreeSo"); 232 if (mallocFunc == nullptr || freeFunc == nullptr) { 233 fprintf(stderr, "function not exist!\n"); 234 exit(0); 235 } 236 ptr = mallocFunc(depth, size); 237 *ptr = 'a'; 238 freeFunc(depth, ptr); 239 if (handle != nullptr) { 240 usleep(100000); // sleep 100000 us 241 dlclose(handle); 242 } 243 } 244 StartMallocProcess()245 void StartMallocProcess() 246 { 247 int processNum = fork(); 248 if (processNum == 0) { 249 while (1) { 250 ApplyForMalloc(unwindDepth_); 251 usleep(500); // sleep 500 us 252 } 253 } else { 254 hookPid_ = processNum; 255 } 256 } 257 StartDlopenProcess()258 void StartDlopenProcess() 259 { 260 int processNum = fork(); 261 if (processNum == 0) { 262 const std::vector<std::string> VEC_SO_PATH { DEFAULT_LIBA_PATH, DEFAULT_LIBB_PATH}; 263 std::string cmdCopyLib{"cp " + DEFAULT_LIBNATIVETEST_PATH + " " + DEFAULT_LIBA_PATH}; 264 system(cmdCopyLib.c_str()); 265 cmdCopyLib = "cp " + DEFAULT_LIBA_PATH + " " + DEFAULT_LIBB_PATH; 266 system(cmdCopyLib.c_str()); 267 while (true) { 268 DlopenAndCloseSo(VEC_SO_PATH[0], LIBA_MALLOC_SIZE, unwindDepth_); 269 DlopenAndCloseSo(VEC_SO_PATH[1], LIBB_MALLOC_SIZE, unwindDepth_); 270 } 271 } else { 272 hookPid_ = processNum; 273 } 274 } 275 DepthCalloc(int depth,int callocSize)276 char* DepthCalloc(int depth, int callocSize) 277 { 278 StaticSpace staticeData; 279 if (depth == 0) { 280 staticeData.data[0] = 1; 281 return reinterpret_cast<char *>(calloc(sizeof(char), callocSize)); 282 } 283 return (DepthCalloc(depth - 1, callocSize)); 284 } 285 ApplyForCalloc(int depth)286 void ApplyForCalloc(int depth) 287 { 288 int callocSize = DEFAULT_CALLOC_SIZE / sizeof(char); 289 char *p = DepthCalloc(depth, callocSize); 290 if (!p) { 291 const int bufSize = 256; 292 char buf[bufSize] = { 0 }; 293 strerror_r(errno, buf, bufSize); 294 HILOG_ERROR(LOG_CORE, "ApplyForCalloc: calloc failure, errno(%d:%s)", errno, buf); 295 return; 296 } 297 DepthFree(depth, p); 298 } 299 StartCallocProcess(int depth)300 void StartCallocProcess(int depth) 301 { 302 int processNum = fork(); 303 if (processNum == 0) { 304 sleep(WAIT_KILL_SIGNL); 305 auto ret = malloc(DEFAULT_MALLOC_SIZE); 306 free(ret); 307 while (1) { 308 ApplyForCalloc(depth); 309 usleep(5000); // sleep 5000 us 310 } 311 } else { 312 hookPid_ = processNum; 313 } 314 } 315 DepthRealloc(int depth,void * p,int reallocSize)316 char *DepthRealloc(int depth, void *p, int reallocSize) 317 { 318 StaticSpace staticeData; 319 if (depth == 0) { 320 staticeData.data[0] = 1; 321 return reinterpret_cast<char *>(realloc(p, reallocSize)); 322 } 323 return (DepthRealloc(depth - 1, p, reallocSize)); 324 } 325 ApplyForRealloc(int depth)326 void ApplyForRealloc(int depth) 327 { 328 int reallocSize = DEFAULT_REALLOC_SIZE; 329 char *p = reinterpret_cast<char *>(malloc(DEFAULT_MALLOC_SIZE)); 330 if (!p) { 331 const int bufSize = 256; 332 char buf[bufSize] = { 0 }; 333 strerror_r(errno, buf, bufSize); 334 HILOG_ERROR(LOG_CORE, "ApplyForRealloc: malloc failure, errno(%d:%s)", errno, buf); 335 return; 336 } 337 char *np = DepthRealloc(depth, p, reallocSize); 338 if (!np) { 339 free(p); 340 const int bufSize = 256; 341 char buf[bufSize] = { 0 }; 342 strerror_r(errno, buf, bufSize); 343 HILOG_ERROR(LOG_CORE, "ApplyForRealloc: realloc failure, errno(%d:%s)", errno, buf); 344 return; 345 } 346 DepthFree(depth, np); 347 } 348 StartReallocProcess(int depth)349 void StartReallocProcess(int depth) 350 { 351 int processNum = fork(); 352 if (processNum == 0) { 353 while (1) { 354 ApplyForRealloc(depth); 355 usleep(500); // sleep 500 us 356 } 357 } else { 358 hookPid_ = processNum; 359 } 360 } 361 Getdata(BufferSplitter & totalbuffer,std::vector<std::string> & hookVec,char delimiter)362 bool Getdata(BufferSplitter& totalbuffer, std::vector<std::string>& hookVec, char delimiter) 363 { 364 totalbuffer.NextWord(delimiter); 365 if (!totalbuffer.CurWord()) { 366 return false; 367 } 368 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 369 hookVec.push_back(curWord); 370 return true; 371 } 372 StartAndStopHook()373 void StartAndStopHook() 374 { 375 sleep(1); 376 StartDaemonProcessArgs(); 377 sleep(1); 378 std::string cmd = "kill -36 " + std::to_string(hookPid_); 379 system(cmd.c_str()); 380 381 sleep(SLEEP_TIME); // 等待生成文本 382 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 383 system(cmdEnd.c_str()); 384 sleep(WAIT_FLUSH); 385 StopProcess(hookPid_); 386 StopProcess(daemonPid_); 387 } 388 389 int daemonPid_ = -1; 390 int hookPid_ = -1; 391 int modeIndex_ = 0; 392 int unwindDepth_ = 0; 393 int statisticsInterval_ = 0; 394 bool offlineSymbolization_ = false; 395 bool callframeCompress_ = false; 396 bool stringCompress_ = false; 397 bool rawString_ = false; 398 std::string outFile_ = ""; 399 std::string outFileType_ = ""; 400 std::string mode_[2] = {"dwarf", "fp"}; 401 std::vector<char*> command_; 402 }; 403 404 /** 405 * @tc.name: native hook 406 * @tc.desc: Test hook malloc normal process. 407 * @tc.type: FUNC 408 */ 409 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0080, Function | MediumTest | Level1) 410 { 411 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 412 unwindDepth_ = 30; 413 outFileType_ = "malloc_"; 414 modeIndex_ = i; // 0 is dwarf, 1 is fp mode 415 StartMallocProcess(); 416 StartAndStopHook(); 417 418 int32_t ret = ReadFile(outFile_); 419 ASSERT_NE(ret, -1); 420 421 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 422 std::vector<std::string> hookVec; 423 std::string addr = ""; 424 int depth = 0; 425 int addrPos = 3; 426 bool isFirstHook = true; 427 do { 428 char delimiter = ';'; 429 Getdata(totalbuffer, hookVec, delimiter); 430 431 if (hookVec[0] == "malloc" && !isFirstHook) { 432 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 433 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 434 } 435 delimiter = '\n'; 436 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 437 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 438 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); // 4: fifth hook data, default malloc size 439 440 addr = hookVec[addrPos]; 441 depth = 0; 442 } else if (hookVec[0] == "free" && !isFirstHook) { 443 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 444 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 445 } 446 delimiter = '\n'; 447 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 448 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 449 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 450 EXPECT_EQ(depth, DEFAULT_DEPTH); 451 452 isFirstHook = false; 453 addr = ""; 454 depth = 0; 455 } else { 456 depth++; 457 } 458 459 hookVec.clear(); 460 } while (totalbuffer.NextLine()); 461 } 462 } 463 464 /** 465 * @tc.name: native hook 466 * @tc.desc: Test hook calloc normal process. 467 * @tc.type: FUNC 468 */ 469 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0090, Function | MediumTest | Level3) 470 { 471 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 472 int setDepth = 1; 473 unwindDepth_ = 100; 474 outFileType_ = "calloc_"; 475 modeIndex_ = i; 476 StartCallocProcess(setDepth); 477 StartAndStopHook(); 478 479 int32_t ret = ReadFile(outFile_); 480 ASSERT_NE(ret, -1); 481 482 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 483 std::vector<std::string> hookVec; 484 std::string addr = ""; 485 int depth = 0; 486 int addrPos = 3; 487 bool isFirstHook = true; 488 do { 489 char delimiter = ';'; 490 Getdata(totalbuffer, hookVec, delimiter); 491 492 if (hookVec[0] == "malloc" && !isFirstHook) { 493 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 494 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 495 } 496 delimiter = '\n'; 497 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 498 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 499 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_CALLOC_SIZE); // 4: fifth hook data, default malloc size 500 501 addr = hookVec[addrPos]; 502 depth = 0; 503 } else if (hookVec[0] == "free" && !isFirstHook) { 504 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 505 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 506 } 507 delimiter = '\n'; 508 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 509 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 510 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 511 EXPECT_GE(depth, CALLOC_DEPTH); 512 513 isFirstHook = false; 514 addr = ""; 515 depth = 0; 516 } else { 517 depth++; 518 } 519 520 hookVec.clear(); 521 } while (totalbuffer.NextLine()); 522 } 523 } 524 525 /** 526 * @tc.name: native hook 527 * @tc.desc: Test hook realloc normal process. 528 * @tc.type: FUNC 529 */ 530 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0100, Function | MediumTest | Level3) 531 { 532 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 533 int setDepth = 100; 534 outFileType_ = "realloc_"; 535 modeIndex_ = i; 536 StartReallocProcess(setDepth); 537 StartAndStopHook(); 538 539 int32_t ret = ReadFile(outFile_); 540 ASSERT_NE(ret, -1); 541 542 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 543 std::vector<std::string> hookVec; 544 std::string mallocAddr = ""; 545 std::string reallocAddr = ""; 546 int depth = 0; 547 int addrPos = 3; 548 bool isFirstHook = true; 549 bool isRealloc = false; 550 do { 551 char delimiter = ';'; 552 Getdata(totalbuffer, hookVec, delimiter); 553 554 if (hookVec[0] == "malloc" && !isFirstHook) { 555 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 556 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 557 } 558 delimiter = '\n'; 559 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 560 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 561 562 if (isRealloc) { 563 reallocAddr = hookVec[addrPos]; 564 // 4: fifth hook data, default malloc size 565 ASSERT_GE(atoi(hookVec[4].c_str()), DEFAULT_REALLOC_SIZE); 566 EXPECT_GE(depth, REALLOC_DEPTH); 567 isFirstHook = false; 568 } else { 569 mallocAddr = hookVec[addrPos]; 570 // 4: fifth hook data, default malloc size 571 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); 572 } 573 574 isRealloc = true; 575 depth = 0; 576 } else if (hookVec[0] == "free" && !isFirstHook) { 577 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 578 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 579 } 580 delimiter = '\n'; 581 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 582 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 583 584 if (isRealloc) { 585 EXPECT_STREQ(hookVec[addrPos].c_str(), reallocAddr.c_str()); 586 reallocAddr = ""; 587 } else { 588 EXPECT_STREQ(hookVec[addrPos].c_str(), mallocAddr.c_str()); 589 mallocAddr = ""; 590 } 591 592 isRealloc = false; 593 depth = 0; 594 } else { 595 depth++; 596 } 597 598 hookVec.clear(); 599 } while (totalbuffer.NextLine()); 600 } 601 } 602 603 /** 604 * @tc.name: native hook 605 * @tc.desc: Test hook dlopen normal process. 606 * @tc.type: FUNC 607 */ 608 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0110, Function | MediumTest | Level3) 609 { 610 for (size_t i = 0; i < 2; ++i) { 611 unwindDepth_ = 6; 612 outFileType_ = "dlopen_"; 613 modeIndex_ = i; 614 StartDlopenProcess(); 615 StartAndStopHook(); 616 std::ifstream infile; 617 infile.open(outFile_, std::ios::in); 618 EXPECT_TRUE(infile.is_open()); 619 std::string buf; 620 uint8_t mallocPos = 0; 621 uint8_t mallocSizePos = 6; 622 uint8_t libUnwindDepth = 3; 623 while (getline(infile, buf)) 624 { 625 std::vector<std::string>& resultVec = StringSplit(buf); 626 if (resultVec[mallocPos] == "malloc") { 627 if (resultVec[mallocSizePos] == std::to_string(LIBA_MALLOC_SIZE)) { 628 std::cout << buf << std::endl; 629 for (size_t i = 0; i < libUnwindDepth; i++) { 630 getline(infile, buf); 631 } 632 std::cout << buf << std::endl; 633 EXPECT_TRUE(buf.find("liba.z.so") != std::string::npos); 634 } else if (resultVec[mallocSizePos] == std::to_string(LIBB_MALLOC_SIZE)) { 635 std::cout << buf << std::endl; 636 for (size_t i = 0; i < libUnwindDepth; i++) { 637 getline(infile, buf); 638 } 639 std::cout << buf << std::endl; 640 EXPECT_TRUE(buf.find("libb.z.so") != std::string::npos); 641 } 642 } 643 } 644 } 645 } 646 647 /** 648 * @tc.name: native hook 649 * @tc.desc: Test hook statistics data normal process. 650 * @tc.type: FUNC 651 */ 652 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0120, Function | MediumTest | Level1) 653 { 654 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 655 unwindDepth_ = 10; 656 statisticsInterval_ = 1; 657 outFileType_ = "statistics_interval_"; 658 modeIndex_ = i; 659 StartMallocProcess(); 660 sleep(1); 661 StartDaemonProcessArgs(); 662 sleep(1); 663 std::string cmd = "kill -36 " + std::to_string(hookPid_); 664 system(cmd.c_str()); 665 666 sleep(SLEEP_TIME); // 等待生成文本 667 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 668 system(cmdEnd.c_str()); 669 sleep(WAIT_FLUSH); 670 StopProcess(hookPid_); 671 cmdEnd = "kill -2 " + std::to_string(daemonPid_); 672 system(cmdEnd.c_str()); 673 674 std::ifstream infile; 675 infile.open(outFile_, std::ios::in); 676 EXPECT_TRUE(infile.is_open()); 677 std::string buf; 678 std::string expectCallStackId; 679 std::string statisticsCallStackId; 680 while (getline(infile, buf)) { 681 if (buf.find("stack_map") != std::string::npos) { 682 if (!expectCallStackId.empty()) { 683 continue; 684 } 685 getline(infile, buf); // read stack_map id 686 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 687 expectCallStackId = resultVec[1]; 688 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 689 } else if (buf.find("statistics_event") != std::string::npos) { 690 getline(infile, buf); // read statistics_event pid 691 getline(infile, buf); // read statistics_event callstack_id 692 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 693 statisticsCallStackId = resultVec[1]; 694 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 695 if (expectCallStackId == statisticsCallStackId) { 696 break; 697 } 698 } 699 } 700 getline(infile, buf); // read statistics_event apply_count 701 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 702 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 703 std::cout << "applyCount: " << applyCount << std::endl; 704 EXPECT_TRUE(applyCount > 0); 705 } 706 } 707 708 /** 709 * @tc.name: native hook 710 * @tc.desc: Test hook offline symbolization data normal process. 711 * @tc.type: FUNC 712 */ 713 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0130, Function | MediumTest | Level1) 714 { 715 for (size_t i = 0; i < 2; ++i) { 716 unwindDepth_ = 10; 717 outFileType_ = "offline_symbolization_"; 718 modeIndex_ = i; 719 offlineSymbolization_ = true; 720 StartMallocProcess(); 721 StartAndStopHook(); 722 723 std::ifstream infile; 724 infile.open(outFile_, std::ios::in); 725 EXPECT_TRUE(infile.is_open()); 726 std::string buf; 727 std::string symTable; 728 std::string strTable; 729 std::string ipString; 730 while (getline(infile, buf)) { 731 if (buf.find("stack_map") != std::string::npos) { 732 getline(infile, buf); // read stack map id 733 getline(infile, buf); // read stack map ip 734 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 735 ipString = resultVec[0]; 736 // delete whitespace characters 737 ipString.erase(std::remove(ipString.begin(), ipString.end(), ' '), ipString.end()); 738 EXPECT_TRUE(ipString == "ip"); 739 } else if (buf.find("sym_table") != std::string::npos) { 740 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 741 symTable = resultVec[1]; 742 EXPECT_TRUE(symTable.size() > 0); 743 } else if (buf.find("str_table") != std::string::npos) { 744 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 745 strTable = resultVec[1]; 746 EXPECT_TRUE(strTable.size() > 0); 747 if (ipString == "ip" && symTable.size()) { 748 break; 749 } 750 } 751 } 752 } 753 } 754 755 /** 756 * @tc.name: native hook 757 * @tc.desc: Test hook callframe compress normal process. 758 * @tc.type: FUNC 759 */ 760 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0140, Function | MediumTest | Level3) 761 { 762 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 763 unwindDepth_ = 6; 764 outFileType_ = "callframecompress_"; 765 modeIndex_ = i; 766 callframeCompress_ = true; 767 StartMallocProcess(); 768 StartAndStopHook(); 769 770 std::ifstream infile; 771 infile.open(outFile_, std::ios::in); 772 EXPECT_TRUE(infile.is_open()); 773 std::string buf; 774 bool findSymbolName; 775 bool findfilePath; 776 bool findFrameMap; 777 bool findStackMap; 778 while (getline(infile, buf)) 779 { 780 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 781 findSymbolName = true; 782 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 783 findfilePath = true; 784 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 785 findFrameMap = true; 786 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 787 findStackMap = true; 788 if (findSymbolName && findfilePath && findFrameMap) { 789 break; 790 } 791 } 792 } 793 EXPECT_TRUE(findSymbolName); 794 EXPECT_TRUE(findfilePath); 795 EXPECT_TRUE(findFrameMap); 796 EXPECT_TRUE(findStackMap); 797 } 798 } 799 800 /** 801 * @tc.name: native hook 802 * @tc.desc: Test hook string compress normal process. 803 * @tc.type: FUNC 804 */ 805 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0150, Function | MediumTest | Level3) 806 { 807 for (size_t i = 0; i < 2; ++i) { 808 unwindDepth_ = 6; 809 outFileType_ = "stringcompress_"; 810 modeIndex_ = i; 811 stringCompress_ = true; 812 StartMallocProcess(); 813 StartAndStopHook(); 814 815 std::ifstream infile; 816 infile.open(outFile_, std::ios::in); 817 EXPECT_TRUE(infile.is_open()); 818 std::string buf; 819 bool findFrameInfo; 820 bool findSymbolNameId; 821 while (getline(infile, buf)) 822 { 823 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 824 findFrameInfo = true; 825 } else if (!findSymbolNameId || buf.find("symbol_name_id") != std::string::npos) { 826 findSymbolNameId = true; 827 if (findFrameInfo) { 828 break; 829 } 830 } 831 } 832 EXPECT_TRUE(findFrameInfo); 833 EXPECT_TRUE(findSymbolNameId); 834 } 835 } 836 837 /** 838 * @tc.name: native hook 839 * @tc.desc: Test hook raw string normal process. 840 * @tc.type: FUNC 841 */ 842 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0160, Function | MediumTest | Level3) 843 { 844 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 845 unwindDepth_ = 6; 846 outFileType_ = "rawstring_"; 847 modeIndex_ = i; 848 rawString_ = true; 849 StartMallocProcess(); 850 StartAndStopHook(); 851 852 std::ifstream infile; 853 infile.open(outFile_, std::ios::in); 854 EXPECT_TRUE(infile.is_open()); 855 std::string buf; 856 bool findFrameInfo; 857 bool findSymbolName; 858 while (getline(infile, buf)) 859 { 860 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 861 findFrameInfo = true; 862 } else if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 863 findSymbolName = true; 864 if (findFrameInfo) { 865 break; 866 } 867 } 868 } 869 EXPECT_TRUE(findFrameInfo); 870 EXPECT_TRUE(findSymbolName); 871 } 872 } 873 } 874 875 #pragma clang optimize on 876