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