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