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