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 WAIT_TIME = 5; 52 constexpr int MALLOC_GET_DATE_SIZE = 3; 53 constexpr int FREE_GET_DATA_SIZE = 2; 54 constexpr int START_JS_REPORT = 1; 55 std::unique_ptr<uint8_t[]> g_buffer = std::make_unique<uint8_t[]>(BUFFER_SIZE); 56 const std::string DEFAULT_PATH("/data/local/tmp/"); 57 #ifdef __aarch64__ 58 const std::string DEFAULT_LIBA_PATH("/data/local/tmp/liba.z.so"); 59 const std::string DEFAULT_LIBB_PATH("/data/local/tmp/libb.z.so"); 60 const int LIBA_MALLOC_SIZE = 888; 61 const int LIBB_MALLOC_SIZE = 666; 62 #endif 63 const std::string DEFAULT_LIBNATIVETEST_PATH("/data/local/tmp/libnativetest_so.z.so"); 64 typedef char* (*DepthMallocSo)(int depth, int mallocSize); 65 typedef void (*DepthFreeSo)(int depth, char *p); 66 67 using StaticSpace = struct { 68 int data[DATA_SIZE]; 69 } ; 70 71 class CheckHookDataTest : public ::testing::Test { 72 public: SetUpTestCase()73 static void SetUpTestCase() {} TearDownTestCase()74 static void TearDownTestCase() {} 75 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 #ifdef __aarch64__ StartDlopenProcess()293 void StartDlopenProcess() 294 { 295 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 296 return; 297 } 298 int processNum = fork(); 299 if (processNum == 0) { 300 const std::vector<std::string> VEC_SO_PATH { DEFAULT_LIBA_PATH, DEFAULT_LIBB_PATH}; 301 std::string cmdCopyLib{"cp " + DEFAULT_LIBNATIVETEST_PATH + " " + DEFAULT_LIBA_PATH}; 302 system(cmdCopyLib.c_str()); 303 cmdCopyLib = "cp " + DEFAULT_LIBA_PATH + " " + DEFAULT_LIBB_PATH; 304 system(cmdCopyLib.c_str()); 305 while (true) { 306 DlopenAndCloseSo(VEC_SO_PATH[0], LIBA_MALLOC_SIZE, unwindDepth_); 307 DlopenAndCloseSo(VEC_SO_PATH[1], LIBB_MALLOC_SIZE, unwindDepth_); 308 } 309 } else { 310 hookPid_ = processNum; 311 } 312 } 313 #endif 314 DepthCalloc(int depth,int callocSize)315 char* DepthCalloc(int depth, int callocSize) 316 { 317 StaticSpace staticeData; 318 if (depth == 0) { 319 staticeData.data[0] = 1; 320 return reinterpret_cast<char *>(calloc(sizeof(char), callocSize)); 321 } 322 return (DepthCalloc(depth - 1, callocSize)); 323 } 324 ApplyForCalloc(int depth)325 void ApplyForCalloc(int depth) 326 { 327 int callocSize = DEFAULT_CALLOC_SIZE / sizeof(char); 328 char *p = DepthCalloc(depth, callocSize); 329 if (!p) { 330 const int bufSize = 256; 331 char buf[bufSize] = { 0 }; 332 strerror_r(errno, buf, bufSize); 333 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForCalloc: calloc failure, errno(%d:%s)", errno, buf); 334 return; 335 } 336 DepthFree(depth, p); 337 } 338 StartCallocProcess(int depth)339 void StartCallocProcess(int depth) 340 { 341 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 342 return; 343 } 344 int processNum = fork(); 345 if (processNum == 0) { 346 int firstSleep = 3; // avoid malloc before sending kill -36 signal 347 int secondSleep = 2; 348 sleep(firstSleep); 349 sleep(secondSleep); 350 auto ret = malloc(DEFAULT_MALLOC_SIZE); 351 free(ret); 352 while (1) { 353 ApplyForCalloc(depth); 354 usleep(5000); // sleep 5000 us 355 } 356 } else { 357 hookPid_ = processNum; 358 } 359 } 360 DepthRealloc(int depth,void * p,int reallocSize)361 char *DepthRealloc(int depth, void *p, int reallocSize) 362 { 363 StaticSpace staticeData; 364 if (depth == 0) { 365 staticeData.data[0] = 1; 366 return reinterpret_cast<char *>(realloc(p, reallocSize)); 367 } 368 return (DepthRealloc(depth - 1, p, reallocSize)); 369 } 370 ApplyForRealloc(int depth)371 void ApplyForRealloc(int depth) 372 { 373 int reallocSize = DEFAULT_REALLOC_SIZE; 374 char *p = reinterpret_cast<char *>(malloc(DEFAULT_MALLOC_SIZE)); 375 if (!p) { 376 const int bufSize = 256; 377 char buf[bufSize] = { 0 }; 378 strerror_r(errno, buf, bufSize); 379 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForRealloc: malloc failure, errno(%d:%s)", errno, buf); 380 return; 381 } 382 char *np = DepthRealloc(depth, p, reallocSize); 383 if (!np) { 384 free(p); 385 const int bufSize = 256; 386 char buf[bufSize] = { 0 }; 387 strerror_r(errno, buf, bufSize); 388 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForRealloc: realloc failure, errno(%d:%s)", errno, buf); 389 return; 390 } 391 DepthFree(depth, np); 392 } 393 StartReallocProcess(int depth)394 void StartReallocProcess(int depth) 395 { 396 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 397 return; 398 } 399 int processNum = fork(); 400 if (processNum == 0) { 401 while (1) { 402 ApplyForRealloc(depth); 403 usleep(5000); // sleep 5000 us 404 } 405 } else { 406 hookPid_ = processNum; 407 } 408 } 409 Getdata(BufferSplitter & totalbuffer,std::vector<std::string> & hookVec,char delimiter)410 bool Getdata(BufferSplitter& totalbuffer, std::vector<std::string>& hookVec, char delimiter) 411 { 412 totalbuffer.NextWord(delimiter); 413 if (!totalbuffer.CurWord()) { 414 return false; 415 } 416 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 417 hookVec.push_back(curWord); 418 return true; 419 } 420 StartAndStopHook()421 void StartAndStopHook() 422 { 423 #ifdef COVERAGE_TEST 424 const int coverageSleepTime = 5; // sleep 5s 425 sleep(coverageSleepTime); 426 StartDaemonProcessArgs(); 427 sleep(coverageSleepTime); 428 #else 429 sleep(1); 430 StartDaemonProcessArgs(); 431 sleep(WAIT_TIME); 432 #endif 433 std::string cmd = "kill -36 " + std::to_string(hookPid_); 434 system(cmd.c_str()); 435 436 sleep(SLEEP_TIME); // 等待生成文本 437 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 438 system(cmdEnd.c_str()); 439 #ifdef COVERAGE_TEST 440 const int waitFlushTime = 5; // sleep 5s 441 sleep(waitFlushTime); 442 #else 443 sleep(WAIT_FLUSH); 444 #endif 445 StopProcess(hookPid_); 446 StopProcess(daemonPid_); 447 } 448 int daemonPid_ = -1; 449 int hookPid_ = -1; 450 int modeIndex_ = 0; 451 int unwindDepth_ = 0; 452 int statisticsInterval_ = 0; 453 int sampleInterval_ = 0; 454 bool jsReport_ = false; 455 int jsMaxDepth_ = 0; 456 int mallocFreeMatchingInterval_ = 0; 457 bool offlineSymbolization_ = false; 458 bool callframeCompress_ = false; 459 bool stringCompress_ = false; 460 bool rawString_ = false; 461 bool responseLibraryMode_ = false; 462 std::string outFile_ = ""; 463 std::string outFileType_ = ""; 464 std::string mode_[2] = {"dwarf", "fp"}; 465 std::vector<char*> command_; 466 }; 467 468 /** 469 * @tc.name: native hook 470 * @tc.desc: Test hook malloc normal process. 471 * @tc.type: FUNC 472 */ 473 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0080, Function | MediumTest | Level1) 474 { 475 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 476 unwindDepth_ = 30; 477 outFileType_ = "malloc_"; 478 modeIndex_ = i; // 0 is dwarf, 1 is fp mode 479 StartMallocProcess(); 480 StartAndStopHook(); 481 482 int32_t ret = ReadFile(outFile_); 483 ASSERT_NE(ret, -1); 484 485 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 486 std::vector<std::string> hookVec; 487 std::string addr = ""; 488 int depth = 0; 489 int addrPos = 3; 490 bool isFirstHook = true; 491 do { 492 char delimiter = ';'; 493 Getdata(totalbuffer, hookVec, delimiter); 494 495 if (hookVec[0] == "malloc" && !isFirstHook) { 496 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 497 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 498 } 499 delimiter = '\n'; 500 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 501 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 502 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); // 4: fifth hook data, default malloc size 503 504 addr = hookVec[addrPos]; 505 depth = 0; 506 } else if (hookVec[0] == "free" && !isFirstHook) { 507 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 508 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 509 } 510 delimiter = '\n'; 511 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 512 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 513 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 514 EXPECT_EQ(depth, DEFAULT_DEPTH); 515 516 isFirstHook = false; 517 addr = ""; 518 depth = 0; 519 } else { 520 depth++; 521 } 522 523 hookVec.clear(); 524 } while (totalbuffer.NextLine()); 525 } 526 } 527 528 /** 529 * @tc.name: native hook 530 * @tc.desc: Test hook calloc normal process. 531 * @tc.type: FUNC 532 */ 533 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0090, Function | MediumTest | Level3) 534 { 535 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 536 int setDepth = 1; 537 unwindDepth_ = 100; 538 outFileType_ = "calloc_"; 539 modeIndex_ = i; 540 StartCallocProcess(setDepth); 541 StartAndStopHook(); 542 543 int32_t ret = ReadFile(outFile_); 544 ASSERT_NE(ret, -1); 545 546 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 547 std::vector<std::string> hookVec; 548 std::string addr = ""; 549 int depth = 0; 550 int addrPos = 3; 551 bool isFirstHook = true; 552 do { 553 char delimiter = ';'; 554 Getdata(totalbuffer, hookVec, delimiter); 555 556 if (hookVec[0] == "malloc" && !isFirstHook) { 557 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 558 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 559 } 560 delimiter = '\n'; 561 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 562 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 563 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_CALLOC_SIZE); // 4: fifth hook data, default malloc size 564 565 addr = hookVec[addrPos]; 566 depth = 0; 567 } else if (hookVec[0] == "free" && !isFirstHook) { 568 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 569 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 570 } 571 delimiter = '\n'; 572 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 573 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 574 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 575 EXPECT_GE(depth, CALLOC_DEPTH); 576 577 isFirstHook = false; 578 addr = ""; 579 depth = 0; 580 } else { 581 depth++; 582 } 583 584 hookVec.clear(); 585 } while (totalbuffer.NextLine()); 586 } 587 } 588 589 /** 590 * @tc.name: native hook 591 * @tc.desc: Test hook realloc normal process. 592 * @tc.type: FUNC 593 */ 594 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0100, Function | MediumTest | Level3) 595 { 596 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 597 int setDepth = 100; 598 outFileType_ = "realloc_"; 599 modeIndex_ = i; 600 StartReallocProcess(setDepth); 601 StartAndStopHook(); 602 603 int32_t ret = ReadFile(outFile_); 604 ASSERT_NE(ret, -1); 605 606 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 607 std::vector<std::string> hookVec; 608 std::string mallocAddr = ""; 609 std::string reallocAddr = ""; 610 int depth = 0; 611 int addrPos = 3; 612 bool isFirstHook = true; 613 bool isRealloc = false; 614 do { 615 char delimiter = ';'; 616 Getdata(totalbuffer, hookVec, delimiter); 617 618 if (hookVec[0] == "malloc" && !isFirstHook) { 619 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 620 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 621 } 622 delimiter = '\n'; 623 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 624 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 625 626 if (isRealloc) { 627 reallocAddr = hookVec[addrPos]; 628 // 4: fifth hook data, default malloc size 629 ASSERT_GE(atoi(hookVec[4].c_str()), DEFAULT_REALLOC_SIZE); 630 EXPECT_GE(depth, REALLOC_DEPTH); 631 isFirstHook = false; 632 } else { 633 mallocAddr = hookVec[addrPos]; 634 // 4: fifth hook data, default malloc size 635 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); 636 } 637 638 isRealloc = true; 639 depth = 0; 640 } else if (hookVec[0] == "free" && !isFirstHook) { 641 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 642 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 643 } 644 delimiter = '\n'; 645 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 646 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 647 648 if (isRealloc) { 649 EXPECT_STREQ(hookVec[addrPos].c_str(), reallocAddr.c_str()); 650 reallocAddr = ""; 651 } else { 652 EXPECT_STREQ(hookVec[addrPos].c_str(), mallocAddr.c_str()); 653 mallocAddr = ""; 654 } 655 656 isRealloc = false; 657 depth = 0; 658 } else { 659 depth++; 660 } 661 662 hookVec.clear(); 663 } while (totalbuffer.NextLine()); 664 } 665 } 666 667 /** 668 * @tc.name: native hook 669 * @tc.desc: Test hook dlopen normal process. 670 * @tc.type: FUNC 671 */ 672 #ifdef __aarch64__ 673 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0110, Function | MediumTest | Level3) 674 { 675 for (size_t i = 1; i < 2; ++i) { 676 unwindDepth_ = 6; 677 outFileType_ = "dlopen_"; 678 modeIndex_ = i; 679 StartDlopenProcess(); 680 StartAndStopHook(); 681 std::ifstream infile; 682 infile.open(outFile_, std::ios::in); 683 EXPECT_TRUE(infile.is_open()); 684 std::string buf; 685 uint8_t mallocPos = 0; 686 uint8_t mallocSizePos = 6; 687 uint8_t libUnwindDepth = 3; 688 while (getline(infile, buf)) 689 { 690 std::vector<std::string>& resultVec = StringSplit(buf); 691 if (resultVec[mallocPos] == "malloc") { 692 if (resultVec[mallocSizePos] == std::to_string(LIBA_MALLOC_SIZE)) { 693 std::cout << buf << std::endl; 694 for (size_t i = 0; i < libUnwindDepth; i++) { 695 getline(infile, buf); 696 } 697 std::cout << buf << std::endl; 698 EXPECT_TRUE(buf.find("liba.z.so") != std::string::npos); 699 } else if (resultVec[mallocSizePos] == std::to_string(LIBB_MALLOC_SIZE)) { 700 std::cout << buf << std::endl; 701 for (size_t i = 0; i < libUnwindDepth; i++) { 702 getline(infile, buf); 703 } 704 std::cout << buf << std::endl; 705 EXPECT_TRUE(buf.find("libb.z.so") != std::string::npos); 706 } 707 } 708 } 709 } 710 } 711 #endif 712 713 /** 714 * @tc.name: native hook 715 * @tc.desc: Test hook statistics data normal process. 716 * @tc.type: FUNC 717 */ 718 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0120, Function | MediumTest | Level1) 719 { 720 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 721 unwindDepth_ = 10; 722 statisticsInterval_ = 1; 723 outFileType_ = "statistics_interval_"; 724 modeIndex_ = i; 725 StartMallocProcess(); 726 sleep(1); 727 StartDaemonProcessArgs(); 728 sleep(1); 729 std::string cmd = "kill -36 " + std::to_string(hookPid_); 730 system(cmd.c_str()); 731 732 sleep(SLEEP_TIME); // 等待生成文本 733 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 734 system(cmdEnd.c_str()); 735 sleep(WAIT_FLUSH); 736 StopProcess(hookPid_); 737 syscall(SYS_tkill, daemonPid_, 2); 738 739 std::ifstream infile; 740 infile.open(outFile_, std::ios::in); 741 EXPECT_TRUE(infile.is_open()); 742 std::string buf; 743 std::string expectCallStackId; 744 std::string statisticsCallStackId; 745 while (getline(infile, buf)) { 746 if (buf.find("stack_map") != std::string::npos) { 747 if (!expectCallStackId.empty()) { 748 continue; 749 } 750 getline(infile, buf); // read stack_map id 751 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 752 expectCallStackId = resultVec[1]; 753 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 754 } else if (buf.find("statistics_event") != std::string::npos) { 755 getline(infile, buf); // read statistics_event pid 756 getline(infile, buf); // read statistics_event callstack_id 757 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 758 statisticsCallStackId = resultVec[1]; 759 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 760 if (expectCallStackId == statisticsCallStackId) { 761 break; 762 } 763 } 764 } 765 getline(infile, buf); // read statistics_event apply_count 766 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 767 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 768 std::cout << "applyCount: " << applyCount << std::endl; 769 EXPECT_TRUE(applyCount > 0); 770 } 771 } 772 773 /** 774 * @tc.name: native hook 775 * @tc.desc: Test hook offline symbolization data normal process. 776 * @tc.type: FUNC 777 */ 778 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0130, Function | MediumTest | Level1) 779 { 780 for (size_t i = 0; i < 2; ++i) { 781 unwindDepth_ = 10; 782 outFileType_ = "offline_symbolization_"; 783 modeIndex_ = i; 784 offlineSymbolization_ = true; 785 StartMallocProcess(); 786 StartAndStopHook(); 787 788 std::ifstream infile; 789 infile.open(outFile_, std::ios::in); 790 EXPECT_TRUE(infile.is_open()); 791 std::string buf; 792 std::string symTable; 793 std::string strTable; 794 std::string ipString; 795 while (getline(infile, buf)) { 796 if (buf.find("stack_map") != std::string::npos) { 797 getline(infile, buf); // read stack map id 798 getline(infile, buf); // read stack map ip 799 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 800 ipString = resultVec[0]; 801 // delete whitespace characters 802 ipString.erase(std::remove(ipString.begin(), ipString.end(), ' '), ipString.end()); 803 EXPECT_TRUE(ipString == "ip"); 804 } else if (buf.find("sym_table") != std::string::npos) { 805 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 806 symTable = resultVec[1]; 807 EXPECT_TRUE(symTable.size() > 0); 808 } else if (buf.find("str_table") != std::string::npos) { 809 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 810 strTable = resultVec[1]; 811 EXPECT_TRUE(strTable.size() > 0); 812 if (ipString == "ip" && symTable.size()) { 813 break; 814 } 815 } 816 } 817 } 818 } 819 820 /** 821 * @tc.name: native hook 822 * @tc.desc: Test hook callframe compress normal process. 823 * @tc.type: FUNC 824 */ 825 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0140, Function | MediumTest | Level3) 826 { 827 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 828 unwindDepth_ = 6; 829 outFileType_ = "callframecompress_"; 830 modeIndex_ = i; 831 callframeCompress_ = true; 832 StartMallocProcess(); 833 StartAndStopHook(); 834 835 std::ifstream infile; 836 infile.open(outFile_, std::ios::in); 837 EXPECT_TRUE(infile.is_open()); 838 std::string buf; 839 bool findSymbolName; 840 bool findfilePath; 841 bool findFrameMap; 842 bool findStackMap; 843 while (getline(infile, buf)) 844 { 845 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 846 findSymbolName = true; 847 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 848 findfilePath = true; 849 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 850 findFrameMap = true; 851 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 852 findStackMap = true; 853 if (findSymbolName && findfilePath && findFrameMap) { 854 break; 855 } 856 } 857 } 858 EXPECT_TRUE(findSymbolName); 859 EXPECT_TRUE(findfilePath); 860 EXPECT_TRUE(findFrameMap); 861 EXPECT_TRUE(findStackMap); 862 } 863 } 864 865 /** 866 * @tc.name: native hook 867 * @tc.desc: Test hook string compress normal process. 868 * @tc.type: FUNC 869 */ 870 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0150, Function | MediumTest | Level3) 871 { 872 for (size_t i = 0; i < 2; ++i) { 873 unwindDepth_ = 6; 874 outFileType_ = "stringcompress_"; 875 modeIndex_ = i; 876 stringCompress_ = true; 877 StartMallocProcess(); 878 StartAndStopHook(); 879 880 std::ifstream infile; 881 infile.open(outFile_, std::ios::in); 882 EXPECT_TRUE(infile.is_open()); 883 std::string buf; 884 bool findFrameInfo; 885 bool findSymbolNameId; 886 while (getline(infile, buf)) 887 { 888 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 889 findFrameInfo = true; 890 } else if (!findSymbolNameId || buf.find("symbol_name_id") != std::string::npos) { 891 findSymbolNameId = true; 892 if (findFrameInfo) { 893 break; 894 } 895 } 896 } 897 EXPECT_TRUE(findFrameInfo); 898 EXPECT_TRUE(findSymbolNameId); 899 } 900 } 901 902 /** 903 * @tc.name: native hook 904 * @tc.desc: Test hook raw string normal process. 905 * @tc.type: FUNC 906 */ 907 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0160, Function | MediumTest | Level3) 908 { 909 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 910 unwindDepth_ = 6; 911 outFileType_ = "rawstring_"; 912 modeIndex_ = i; 913 rawString_ = true; 914 StartMallocProcess(); 915 StartAndStopHook(); 916 917 std::ifstream infile; 918 infile.open(outFile_, std::ios::in); 919 EXPECT_TRUE(infile.is_open()); 920 std::string buf; 921 bool findFrameInfo; 922 bool findSymbolName; 923 while (getline(infile, buf)) 924 { 925 if (!findFrameInfo || buf.find("frame_info") != std::string::npos) { 926 findFrameInfo = true; 927 } else if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 928 findSymbolName = true; 929 if (findFrameInfo) { 930 break; 931 } 932 } 933 } 934 EXPECT_TRUE(findFrameInfo); 935 EXPECT_TRUE(findSymbolName); 936 } 937 } 938 939 #ifdef __aarch64__ 940 /** 941 * @tc.name: native hook 942 * @tc.desc: Test hook raw responseLibraryMode normal process. 943 * @tc.type: FUNC 944 */ 945 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0170, Function | MediumTest | Level3) 946 { 947 for (size_t i = 1; i < 2; ++i) { // 1 is fp mode, response_library_mode only fp mode is used 948 unwindDepth_ = 6; 949 outFileType_ = "responseLibraryMode"; 950 modeIndex_ = i; 951 responseLibraryMode_ = true; 952 StartMallocProcess(); 953 StartAndStopHook(); 954 955 std::ifstream infile; 956 infile.open(outFile_, std::ios::in); 957 EXPECT_TRUE(infile.is_open()); 958 std::string buf; 959 uint16_t ipCount = 0; 960 961 while (getline(infile, buf)) { 962 if (buf.find("stack_map") != std::string::npos) { 963 while (getline(infile, buf)) { 964 if (buf.find("ip") != std::string::npos) { 965 ++ipCount; 966 continue; 967 } else if (buf.find("}") != std::string::npos) { 968 break; 969 } 970 } 971 } 972 if (ipCount > 0) { 973 break; 974 } 975 } 976 EXPECT_TRUE(ipCount == 1); // response_library_mode callstack depth only is 1 977 } 978 } 979 #endif 980 981 /** 982 * @tc.name: native hook 983 * @tc.desc: Test hook statistics data normal process. 984 * @tc.type: FUNC 985 */ 986 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0180, Function | MediumTest | Level1) 987 { 988 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 989 unwindDepth_ = 10; 990 statisticsInterval_ = 1; 991 sampleInterval_ = 256; 992 outFileType_ = "sample_interval_"; 993 modeIndex_ = i; 994 StartMallocProcess(); 995 sleep(1); 996 StartDaemonProcessArgs(); 997 sleep(1); 998 std::string cmd = "kill -36 " + std::to_string(hookPid_); 999 system(cmd.c_str()); 1000 1001 sleep(SLEEP_TIME); // 等待生成文本 1002 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 1003 system(cmdEnd.c_str()); 1004 sleep(WAIT_FLUSH); 1005 StopProcess(hookPid_); 1006 syscall(SYS_tkill, daemonPid_, 2); 1007 1008 std::ifstream infile; 1009 infile.open(outFile_, std::ios::in); 1010 EXPECT_TRUE(infile.is_open()); 1011 std::string buf; 1012 std::string expectCallStackId; 1013 std::string statisticsCallStackId; 1014 while (getline(infile, buf)) { 1015 if (buf.find("stack_map") != std::string::npos) { 1016 if (!expectCallStackId.empty()) { 1017 continue; 1018 } 1019 getline(infile, buf); // read stack_map id 1020 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1021 expectCallStackId = resultVec[1]; 1022 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 1023 } else if (buf.find("statistics_event") != std::string::npos) { 1024 getline(infile, buf); // read statistics_event pid 1025 getline(infile, buf); // read statistics_event callstack_id 1026 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1027 statisticsCallStackId = resultVec[1]; 1028 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 1029 if (expectCallStackId == statisticsCallStackId) { 1030 break; 1031 } 1032 } 1033 } 1034 getline(infile, buf); // read statistics_event apply_count 1035 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1036 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 1037 std::cout << "applyCount: " << applyCount << std::endl; 1038 EXPECT_TRUE(applyCount > 0); 1039 } 1040 } 1041 1042 /** 1043 * @tc.name: native hook 1044 * @tc.desc: Test hook alloc free matching interval normal process. 1045 * @tc.type: FUNC 1046 */ 1047 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0190, Function | MediumTest | Level3) 1048 { 1049 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1050 unwindDepth_ = 6; 1051 outFileType_ = "mallocFreeMatchingInterval_"; 1052 modeIndex_ = i; 1053 mallocFreeMatchingInterval_ = 2; 1054 StartMallocProcess(); 1055 StartAndStopHook(); 1056 1057 std::ifstream infile; 1058 infile.open(outFile_, std::ios::in); 1059 EXPECT_TRUE(infile.is_open()); 1060 std::string buf; 1061 bool findSymbolName; 1062 bool findfilePath; 1063 bool findFrameMap; 1064 bool findStackMap; 1065 while (getline(infile, buf)) 1066 { 1067 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 1068 findSymbolName = true; 1069 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 1070 findfilePath = true; 1071 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 1072 findFrameMap = true; 1073 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 1074 findStackMap = true; 1075 if (findSymbolName && findfilePath && findFrameMap) { 1076 break; 1077 } 1078 } 1079 } 1080 EXPECT_TRUE(findSymbolName); 1081 EXPECT_TRUE(findfilePath); 1082 EXPECT_TRUE(findFrameMap); 1083 EXPECT_TRUE(findStackMap); 1084 } 1085 } 1086 1087 1088 /** 1089 * @tc.name: native hook 1090 * @tc.desc: Test hook js statistics data normal process. 1091 * @tc.type: FUNC 1092 */ 1093 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0200, Function | MediumTest | Level1) 1094 { 1095 for (size_t i = 1; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1096 unwindDepth_ = 10; 1097 statisticsInterval_ = 1; 1098 jsReport_ = true; 1099 jsMaxDepth_ = 10; 1100 outFileType_ = "js_report_"; 1101 modeIndex_ = i; 1102 StartMallocProcess(); 1103 sleep(1); 1104 StartDaemonProcessArgs(); 1105 sleep(1); 1106 std::string cmd = "kill -36 " + std::to_string(hookPid_); 1107 system(cmd.c_str()); 1108 1109 sleep(SLEEP_TIME); // 等待生成文本 1110 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 1111 system(cmdEnd.c_str()); 1112 sleep(WAIT_FLUSH); 1113 StopProcess(hookPid_); 1114 syscall(SYS_tkill, daemonPid_, 2); 1115 1116 std::ifstream infile; 1117 infile.open(outFile_, std::ios::in); 1118 EXPECT_TRUE(infile.is_open()); 1119 std::string buf; 1120 std::string expectCallStackId; 1121 std::string statisticsCallStackId; 1122 while (getline(infile, buf)) { 1123 if (buf.find("stack_map") != std::string::npos) { 1124 if (!expectCallStackId.empty()) { 1125 continue; 1126 } 1127 getline(infile, buf); // read stack_map id 1128 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1129 expectCallStackId = resultVec[1]; 1130 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 1131 } else if (buf.find("statistics_event") != std::string::npos) { 1132 getline(infile, buf); // read statistics_event pid 1133 getline(infile, buf); // read statistics_event callstack_id 1134 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1135 statisticsCallStackId = resultVec[1]; 1136 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 1137 if (expectCallStackId == statisticsCallStackId) { 1138 break; 1139 } 1140 } 1141 } 1142 getline(infile, buf); // read statistics_event apply_count 1143 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1144 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 1145 std::cout << "applyCount: " << applyCount << std::endl; 1146 EXPECT_TRUE(applyCount > 0); 1147 } 1148 } 1149 } 1150 1151 #pragma clang optimize on