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 if (!buf.empty()) { 770 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 771 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 772 std::cout << "applyCount: " << applyCount << std::endl; 773 EXPECT_TRUE(applyCount > 0); 774 } 775 sleep(SLEEP_TIME); 776 } 777 } 778 779 /** 780 * @tc.name: native hook 781 * @tc.desc: Test hook offline symbolization data normal process. 782 * @tc.type: FUNC 783 */ 784 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0130, Function | MediumTest | Level1) 785 { 786 for (size_t i = 0; i < 2; ++i) { 787 unwindDepth_ = 10; 788 outFileType_ = "offline_symbolization_"; 789 modeIndex_ = i; 790 offlineSymbolization_ = true; 791 StartMallocProcess(); 792 StartAndStopHook(); 793 794 std::ifstream infile; 795 infile.open(outFile_, std::ios::in); 796 EXPECT_TRUE(infile.is_open()); 797 std::string buf; 798 std::string symTable; 799 std::string strTable; 800 std::string ipString; 801 while (getline(infile, buf)) { 802 if (buf.find("stack_map") != std::string::npos) { 803 getline(infile, buf); // read stack map id 804 getline(infile, buf); // read stack map ip 805 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 806 ipString = resultVec[0]; 807 // delete whitespace characters 808 ipString.erase(std::remove(ipString.begin(), ipString.end(), ' '), ipString.end()); 809 EXPECT_TRUE(ipString == "ip"); 810 } else if (buf.find("sym_table") != std::string::npos) { 811 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 812 symTable = resultVec[1]; 813 EXPECT_TRUE(symTable.size() > 0); 814 } else if (buf.find("str_table") != std::string::npos) { 815 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 816 strTable = resultVec[1]; 817 EXPECT_TRUE(strTable.size() > 0); 818 if (ipString == "ip" && symTable.size()) { 819 break; 820 } 821 } 822 } 823 } 824 } 825 826 /** 827 * @tc.name: native hook 828 * @tc.desc: Test hook callframe compress normal process. 829 * @tc.type: FUNC 830 */ 831 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0140, Function | MediumTest | Level3) 832 { 833 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 834 unwindDepth_ = 6; 835 outFileType_ = "callframecompress_"; 836 modeIndex_ = i; 837 callframeCompress_ = true; 838 StartMallocProcess(); 839 StartAndStopHook(); 840 841 std::ifstream infile; 842 infile.open(outFile_, std::ios::in); 843 EXPECT_TRUE(infile.is_open()); 844 std::string buf; 845 bool findSymbolName; 846 bool findfilePath; 847 bool findFrameMap; 848 bool findStackMap; 849 while (getline(infile, buf)) 850 { 851 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 852 findSymbolName = true; 853 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 854 findfilePath = true; 855 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 856 findFrameMap = true; 857 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 858 findStackMap = true; 859 if (findSymbolName && findfilePath && findFrameMap) { 860 break; 861 } 862 } 863 } 864 EXPECT_TRUE(findSymbolName); 865 EXPECT_TRUE(findfilePath); 866 EXPECT_TRUE(findFrameMap); 867 EXPECT_TRUE(findStackMap); 868 } 869 } 870 871 /** 872 * @tc.name: native hook 873 * @tc.desc: Test hook string compress normal process. 874 * @tc.type: FUNC 875 */ 876 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0150, Function | MediumTest | Level3) 877 { 878 for (size_t i = 0; i < 2; ++i) { 879 unwindDepth_ = 6; 880 outFileType_ = "stringcompress_"; 881 modeIndex_ = i; 882 stringCompress_ = true; 883 StartMallocProcess(); 884 StartAndStopHook(); 885 886 std::ifstream infile; 887 infile.open(outFile_, std::ios::in); 888 EXPECT_TRUE(infile.is_open()); 889 std::string buf; 890 bool findFrameInfo; 891 bool findSymbolNameId; 892 while (getline(infile, buf)) 893 { 894 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 895 findFrameInfo = true; 896 } else if (!findSymbolNameId || buf.find("symbol_name_id") != std::string::npos) { 897 findSymbolNameId = true; 898 if (findFrameInfo) { 899 break; 900 } 901 } 902 } 903 EXPECT_TRUE(findFrameInfo); 904 EXPECT_TRUE(findSymbolNameId); 905 } 906 } 907 908 /** 909 * @tc.name: native hook 910 * @tc.desc: Test hook raw string normal process. 911 * @tc.type: FUNC 912 */ 913 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0160, Function | MediumTest | Level3) 914 { 915 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 916 unwindDepth_ = 6; 917 outFileType_ = "rawstring_"; 918 modeIndex_ = i; 919 rawString_ = true; 920 StartMallocProcess(); 921 StartAndStopHook(); 922 923 std::ifstream infile; 924 infile.open(outFile_, std::ios::in); 925 EXPECT_TRUE(infile.is_open()); 926 std::string buf; 927 bool findFrameInfo; 928 bool findSymbolName; 929 while (getline(infile, buf)) 930 { 931 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 932 findFrameInfo = true; 933 } else if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 934 findSymbolName = true; 935 if (findFrameInfo) { 936 break; 937 } 938 } 939 } 940 EXPECT_TRUE(findFrameInfo); 941 EXPECT_TRUE(findSymbolName); 942 } 943 } 944 945 #ifdef __aarch64__ 946 /** 947 * @tc.name: native hook 948 * @tc.desc: Test hook raw responseLibraryMode normal process. 949 * @tc.type: FUNC 950 */ 951 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0170, Function | MediumTest | Level3) 952 { 953 for (size_t i = 1; i < 2; ++i) { // 1 is fp mode, response_library_mode only fp mode is used 954 unwindDepth_ = 6; 955 outFileType_ = "responseLibraryMode"; 956 modeIndex_ = i; 957 responseLibraryMode_ = true; 958 StartMallocProcess(); 959 StartAndStopHook(); 960 961 std::ifstream infile; 962 infile.open(outFile_, std::ios::in); 963 EXPECT_TRUE(infile.is_open()); 964 std::string buf; 965 uint16_t ipCount = 0; 966 967 while (getline(infile, buf)) { 968 if (buf.find("stack_map") != std::string::npos) { 969 while (getline(infile, buf)) { 970 if (buf.find("ip") != std::string::npos) { 971 ++ipCount; 972 continue; 973 } else if (buf.find("}") != std::string::npos) { 974 break; 975 } 976 } 977 } 978 if (ipCount > 0) { 979 break; 980 } 981 } 982 EXPECT_TRUE(ipCount == 1); // response_library_mode callstack depth only is 1 983 } 984 } 985 #endif 986 987 /** 988 * @tc.name: native hook 989 * @tc.desc: Test hook statistics data normal process. 990 * @tc.type: FUNC 991 */ 992 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0180, Function | MediumTest | Level1) 993 { 994 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 995 unwindDepth_ = 10; 996 statisticsInterval_ = 1; 997 sampleInterval_ = 256; 998 outFileType_ = "sample_interval_"; 999 modeIndex_ = i; 1000 StartMallocProcess(); 1001 sleep(1); 1002 StartDaemonProcessArgs(); 1003 sleep(1); 1004 std::string cmd = "kill -36 " + std::to_string(hookPid_); 1005 system(cmd.c_str()); 1006 1007 sleep(SLEEP_TIME); // 等待生成文本 1008 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 1009 system(cmdEnd.c_str()); 1010 sleep(WAIT_FLUSH); 1011 StopProcess(hookPid_); 1012 syscall(SYS_tkill, daemonPid_, 2); 1013 1014 std::ifstream infile; 1015 infile.open(outFile_, std::ios::in); 1016 EXPECT_TRUE(infile.is_open()); 1017 std::string buf; 1018 std::string expectCallStackId; 1019 std::string statisticsCallStackId; 1020 while (getline(infile, buf)) { 1021 if (buf.find("stack_map") != std::string::npos) { 1022 if (!expectCallStackId.empty()) { 1023 continue; 1024 } 1025 getline(infile, buf); // read stack_map id 1026 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1027 expectCallStackId = resultVec[1]; 1028 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 1029 } else if (buf.find("statistics_event") != std::string::npos) { 1030 getline(infile, buf); // read statistics_event pid 1031 getline(infile, buf); // read statistics_event callstack_id 1032 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1033 statisticsCallStackId = resultVec[1]; 1034 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 1035 if (expectCallStackId == statisticsCallStackId) { 1036 break; 1037 } 1038 } 1039 } 1040 getline(infile, buf); // read statistics_event apply_count 1041 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1042 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 1043 std::cout << "applyCount: " << applyCount << std::endl; 1044 EXPECT_TRUE(applyCount > 0); 1045 sleep(SLEEP_TIME); 1046 } 1047 } 1048 1049 /** 1050 * @tc.name: native hook 1051 * @tc.desc: Test hook alloc free matching interval normal process. 1052 * @tc.type: FUNC 1053 */ 1054 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0190, Function | MediumTest | Level3) 1055 { 1056 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1057 unwindDepth_ = 6; 1058 outFileType_ = "mallocFreeMatchingInterval_"; 1059 modeIndex_ = i; 1060 mallocFreeMatchingInterval_ = 2; 1061 StartMallocProcess(); 1062 StartAndStopHook(); 1063 1064 std::ifstream infile; 1065 infile.open(outFile_, std::ios::in); 1066 EXPECT_TRUE(infile.is_open()); 1067 std::string buf; 1068 bool findSymbolName; 1069 bool findfilePath; 1070 bool findFrameMap; 1071 bool findStackMap; 1072 while (getline(infile, buf)) 1073 { 1074 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 1075 findSymbolName = true; 1076 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 1077 findfilePath = true; 1078 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 1079 findFrameMap = true; 1080 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 1081 findStackMap = true; 1082 if (findSymbolName && findfilePath && findFrameMap) { 1083 break; 1084 } 1085 } 1086 } 1087 EXPECT_TRUE(findSymbolName); 1088 EXPECT_TRUE(findfilePath); 1089 EXPECT_TRUE(findFrameMap); 1090 EXPECT_TRUE(findStackMap); 1091 } 1092 } 1093 1094 1095 /** 1096 * @tc.name: native hook 1097 * @tc.desc: Test hook js statistics data normal process. 1098 * @tc.type: FUNC 1099 */ 1100 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0200, Function | MediumTest | Level1) 1101 { 1102 for (size_t i = 1; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1103 unwindDepth_ = 10; 1104 statisticsInterval_ = 1; 1105 jsReport_ = 1; 1106 jsMaxDepth_ = 10; 1107 outFileType_ = "js_report_"; 1108 modeIndex_ = i; 1109 StartMallocProcess(); 1110 sleep(1); 1111 StartDaemonProcessArgs(); 1112 sleep(1); 1113 std::string cmd = "kill -36 " + std::to_string(hookPid_); 1114 system(cmd.c_str()); 1115 1116 sleep(SLEEP_TIME); // 等待生成文本 1117 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 1118 system(cmdEnd.c_str()); 1119 sleep(WAIT_FLUSH); 1120 StopProcess(hookPid_); 1121 syscall(SYS_tkill, daemonPid_, 2); 1122 1123 std::ifstream infile; 1124 infile.open(outFile_, std::ios::in); 1125 EXPECT_TRUE(infile.is_open()); 1126 std::string buf; 1127 std::string expectCallStackId; 1128 std::string statisticsCallStackId; 1129 while (getline(infile, buf)) { 1130 if (buf.find("stack_map") != std::string::npos) { 1131 if (!expectCallStackId.empty()) { 1132 continue; 1133 } 1134 getline(infile, buf); // read stack_map id 1135 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1136 expectCallStackId = resultVec[1]; 1137 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 1138 } else if (buf.find("statistics_event") != std::string::npos) { 1139 getline(infile, buf); // read statistics_event pid 1140 getline(infile, buf); // read statistics_event callstack_id 1141 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1142 statisticsCallStackId = resultVec[1]; 1143 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 1144 if (expectCallStackId == statisticsCallStackId) { 1145 break; 1146 } 1147 } 1148 } 1149 getline(infile, buf); // read statistics_event apply_count 1150 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1151 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 1152 std::cout << "applyCount: " << applyCount << std::endl; 1153 EXPECT_TRUE(applyCount > 0); 1154 sleep(SLEEP_TIME); 1155 } 1156 } 1157 } 1158 1159 #pragma clang optimize on