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 #ifdef __aarch64__ 57 const std::string DEFAULT_LIBA_PATH("/data/local/tmp/liba.z.so"); 58 const std::string DEFAULT_LIBB_PATH("/data/local/tmp/libb.z.so"); 59 const int LIBA_MALLOC_SIZE = 888; 60 const int LIBB_MALLOC_SIZE = 666; 61 #endif 62 const std::string DEFAULT_LIBNATIVETEST_PATH("/data/local/tmp/libnativetest_so.z.so"); 63 typedef char* (*DepthMallocSo)(int depth, int mallocSize); 64 typedef void (*DepthFreeSo)(int depth, char *p); 65 66 using StaticSpace = struct { 67 int data[DATA_SIZE]; 68 } ; 69 70 class CheckHookDataTest : public ::testing::Test { 71 public: SetUpTestCase()72 static void SetUpTestCase() {} TearDownTestCase()73 static void TearDownTestCase() {} 74 StartDaemonProcessArgs()75 void StartDaemonProcessArgs() 76 { 77 outFile_ = DEFAULT_PATH + "hooktest_"+ outFileType_ + mode_[modeIndex_] + ".txt"; 78 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 79 return; 80 } 81 int processNum = fork(); 82 if (processNum == 0) { 83 int waitProcMills = 300; 84 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "0"); 85 std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills)); 86 command_.push_back(const_cast<char*>(DEFAULT_NATIVE_DAEMON_PATH.c_str())); 87 command_.push_back(const_cast<char*>("-o")); 88 command_.push_back(const_cast<char*>(outFile_.c_str())); 89 command_.push_back(const_cast<char*>("-s")); 90 command_.push_back(const_cast<char*>(std::to_string(SHARE_MEMORY_SIZE).c_str())); 91 command_.push_back(const_cast<char*>("-p")); 92 command_.push_back(const_cast<char*>(std::to_string(hookPid_).c_str())); 93 command_.push_back(const_cast<char*>("-u")); 94 command_.push_back(const_cast<char*>(mode_[modeIndex_].c_str())); 95 if (unwindDepth_ > 0) { 96 command_.push_back(const_cast<char*>("-d")); 97 command_.push_back(const_cast<char*>(std::to_string(unwindDepth_).c_str())); 98 } 99 if (statisticsInterval_ > 0) { 100 command_.push_back(const_cast<char*>("-S")); 101 command_.push_back(const_cast<char*>(std::to_string(statisticsInterval_).c_str())); 102 } 103 if (sampleInterval_ > 0) { 104 command_.push_back(const_cast<char*>("-i")); 105 command_.push_back(const_cast<char*>(std::to_string(sampleInterval_).c_str())); 106 } 107 if (offlineSymbolization_) { 108 command_.push_back(const_cast<char*>("-O")); 109 command_.push_back(const_cast<char*>("true")); 110 } 111 if (callframeCompress_) { 112 command_.push_back(const_cast<char*>("-C")); 113 command_.push_back(const_cast<char*>("true")); 114 } 115 if (stringCompress_) { 116 command_.push_back(const_cast<char*>("-c")); 117 command_.push_back(const_cast<char*>("true")); 118 } 119 if (rawString_) { 120 command_.push_back(const_cast<char*>("-r")); 121 command_.push_back(const_cast<char*>("true")); 122 } 123 if (responseLibraryMode_) { 124 command_.push_back(const_cast<char*>("-so")); 125 command_.push_back(const_cast<char*>("true")); 126 } 127 if (mallocFreeMatchingInterval_ > 0) { 128 command_.push_back(const_cast<char*>("-mfm")); 129 command_.push_back(const_cast<char*>(std::to_string(mallocFreeMatchingInterval_).c_str())); 130 } 131 if (jsReport_) { 132 command_.push_back(const_cast<char*>("-js")); 133 command_.push_back(const_cast<char*>(std::to_string(START_JS_REPORT).c_str())); 134 command_.push_back(const_cast<char*>("-jsd")); 135 command_.push_back(const_cast<char*>(std::to_string(jsMaxDepth_).c_str())); 136 } 137 command_.push_back(nullptr); 138 execv(DEFAULT_NATIVE_DAEMON_PATH.c_str(), command_.data()); 139 _exit(1); 140 } else { 141 daemonPid_ = processNum; 142 } 143 } 144 StringSplit(const std::string & str,char delim=';')145 std::vector<std::string>& StringSplit(const std::string& str, char delim = ';') 146 { 147 std::stringstream ss(str); 148 std::string item; 149 static std::vector<std::string> elems; 150 elems.clear(); 151 while (std::getline(ss, item, delim)) { 152 if (!item.empty()) { 153 elems.push_back(item); 154 } 155 } 156 return elems; 157 } 158 StopProcess(int processNum)159 void StopProcess(int processNum) 160 { 161 std::string stopCmd = "kill -9 " + std::to_string(processNum); 162 system(stopCmd.c_str()); 163 } 164 ReadFile(std::string file)165 int32_t ReadFile(std::string file) 166 { 167 int fd = -1; 168 ssize_t bytesRead = 0; 169 char filePath[PATH_MAX + 1] = {0}; 170 171 if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s", file.c_str()) < 0) { 172 const int bufSize = 256; 173 char buf[bufSize] = { 0 }; 174 strerror_r(errno, buf, bufSize); 175 PROFILER_LOG_ERROR(LOG_CORE, "snprintf_s(%s) error, errno(%d:%s)", file.c_str(), errno, buf); 176 return -1; 177 } 178 179 char* realPath = realpath(filePath, nullptr); 180 if (realPath == nullptr) { 181 const int bufSize = 256; 182 char buf[bufSize] = { 0 }; 183 strerror_r(errno, buf, bufSize); 184 PROFILER_LOG_ERROR(LOG_CORE, "realpath(%s) failed, errno(%d:%s)", file.c_str(), errno, buf); 185 return -1; 186 } 187 188 fd = open(realPath, O_RDONLY | O_CLOEXEC); 189 if (fd == -1) { 190 const int bufSize = 256; 191 char buf[bufSize] = { 0 }; 192 strerror_r(errno, buf, bufSize); 193 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, realPath, errno, buf); 194 return -1; 195 } 196 if (g_buffer == nullptr) { 197 PROFILER_LOG_ERROR(LOG_CORE, "%s:empty address, g_buffer is NULL", __func__); 198 close(fd); 199 return -1; 200 } 201 bytesRead = read(fd, g_buffer.get(), BUFFER_SIZE - 1); 202 if (bytesRead <= 0) { 203 close(fd); 204 PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, realPath, errno); 205 return -1; 206 } 207 close(fd); 208 free(realPath); 209 210 return bytesRead; 211 } 212 DepthFree(int depth,void * p)213 void DepthFree(int depth, void *p) 214 { 215 StaticSpace staticeData; 216 if (depth == 0) { 217 staticeData.data[0] = 1; 218 free(p); 219 return; 220 } 221 return (DepthFree(depth - 1, p)); 222 } 223 DepthMalloc(int depth)224 char *DepthMalloc(int depth) 225 { 226 StaticSpace staticeData; 227 if (depth == 0) { 228 staticeData.data[0] = 1; 229 return reinterpret_cast<char *>(malloc(DEFAULT_MALLOC_SIZE)); 230 } 231 return (DepthMalloc(depth - 1)); 232 } 233 ApplyForMalloc(int depth)234 void ApplyForMalloc(int depth) 235 { 236 char *p = DepthMalloc(depth); 237 if (!p) { 238 const int bufSize = 256; 239 char buf[bufSize] = { 0 }; 240 strerror_r(errno, buf, bufSize); 241 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForMalloc: malloc failure, errno(%d:%s)", errno, buf); 242 return; 243 } 244 DepthFree(depth, p); 245 } 246 247 #ifdef __aarch64__ DlopenAndCloseSo(std::string filePath,int size,int depth)248 void DlopenAndCloseSo(std::string filePath, int size, int depth) 249 { 250 char *ptr = nullptr; 251 void *handle = nullptr; 252 DepthMallocSo mallocFunc = nullptr; 253 DepthFreeSo freeFunc = nullptr; 254 255 handle = dlopen(filePath.data(), RTLD_LAZY); 256 if (handle == nullptr) { 257 fprintf(stderr, "library not exist!\n"); 258 exit(0); 259 } 260 mallocFunc = (DepthMallocSo)dlsym(handle, "DepthMallocSo"); 261 freeFunc = (DepthFreeSo)dlsym(handle, "DepthFreeSo"); 262 if (mallocFunc == nullptr || freeFunc == nullptr) { 263 fprintf(stderr, "function not exist!\n"); 264 exit(0); 265 } 266 ptr = mallocFunc(depth, size); 267 *ptr = 'a'; 268 freeFunc(depth, ptr); 269 if (handle != nullptr) { 270 usleep(100000); // sleep 100000 us 271 dlclose(handle); 272 } 273 } 274 #endif 275 StartMallocProcess()276 void StartMallocProcess() 277 { 278 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 279 return; 280 } 281 int processNum = fork(); 282 if (processNum == 0) { 283 while (1) { 284 ApplyForMalloc(unwindDepth_); 285 usleep(5000); // sleep 5000 us 286 } 287 } else { 288 hookPid_ = processNum; 289 } 290 } 291 #ifdef __aarch64__ StartDlopenProcess()292 void StartDlopenProcess() 293 { 294 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 295 return; 296 } 297 int processNum = fork(); 298 if (processNum == 0) { 299 const std::vector<std::string> VEC_SO_PATH { DEFAULT_LIBA_PATH, DEFAULT_LIBB_PATH}; 300 std::string cmdCopyLib{"cp " + DEFAULT_LIBNATIVETEST_PATH + " " + DEFAULT_LIBA_PATH}; 301 system(cmdCopyLib.c_str()); 302 cmdCopyLib = "cp " + DEFAULT_LIBA_PATH + " " + DEFAULT_LIBB_PATH; 303 system(cmdCopyLib.c_str()); 304 while (true) { 305 DlopenAndCloseSo(VEC_SO_PATH[0], LIBA_MALLOC_SIZE, unwindDepth_); 306 DlopenAndCloseSo(VEC_SO_PATH[1], LIBB_MALLOC_SIZE, unwindDepth_); 307 } 308 } else { 309 hookPid_ = processNum; 310 } 311 } 312 #endif 313 DepthCalloc(int depth,int callocSize)314 char* DepthCalloc(int depth, int callocSize) 315 { 316 StaticSpace staticeData; 317 if (depth == 0) { 318 staticeData.data[0] = 1; 319 return reinterpret_cast<char *>(calloc(sizeof(char), callocSize)); 320 } 321 return (DepthCalloc(depth - 1, callocSize)); 322 } 323 ApplyForCalloc(int depth)324 void ApplyForCalloc(int depth) 325 { 326 int callocSize = DEFAULT_CALLOC_SIZE / sizeof(char); 327 char *p = DepthCalloc(depth, callocSize); 328 if (!p) { 329 const int bufSize = 256; 330 char buf[bufSize] = { 0 }; 331 strerror_r(errno, buf, bufSize); 332 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForCalloc: calloc failure, errno(%d:%s)", errno, buf); 333 return; 334 } 335 DepthFree(depth, p); 336 } 337 StartCallocProcess(int depth)338 void StartCallocProcess(int depth) 339 { 340 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 341 return; 342 } 343 int processNum = fork(); 344 if (processNum == 0) { 345 int firstSleep = 3; // avoid malloc before sending kill -36 signal 346 int secondSleep = 2; 347 sleep(firstSleep); 348 sleep(secondSleep); 349 auto ret = malloc(DEFAULT_MALLOC_SIZE); 350 free(ret); 351 while (1) { 352 ApplyForCalloc(depth); 353 usleep(5000); // sleep 5000 us 354 } 355 } else { 356 hookPid_ = processNum; 357 } 358 } 359 DepthRealloc(int depth,void * p,int reallocSize)360 char *DepthRealloc(int depth, void *p, int reallocSize) 361 { 362 StaticSpace staticeData; 363 if (depth == 0) { 364 staticeData.data[0] = 1; 365 return reinterpret_cast<char *>(realloc(p, reallocSize)); 366 } 367 return (DepthRealloc(depth - 1, p, reallocSize)); 368 } 369 ApplyForRealloc(int depth)370 void ApplyForRealloc(int depth) 371 { 372 int reallocSize = DEFAULT_REALLOC_SIZE; 373 char *p = reinterpret_cast<char *>(malloc(DEFAULT_MALLOC_SIZE)); 374 if (!p) { 375 const int bufSize = 256; 376 char buf[bufSize] = { 0 }; 377 strerror_r(errno, buf, bufSize); 378 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForRealloc: malloc failure, errno(%d:%s)", errno, buf); 379 return; 380 } 381 char *np = DepthRealloc(depth, p, reallocSize); 382 if (!np) { 383 free(p); 384 const int bufSize = 256; 385 char buf[bufSize] = { 0 }; 386 strerror_r(errno, buf, bufSize); 387 PROFILER_LOG_ERROR(LOG_CORE, "ApplyForRealloc: realloc failure, errno(%d:%s)", errno, buf); 388 return; 389 } 390 DepthFree(depth, np); 391 } 392 StartReallocProcess(int depth)393 void StartReallocProcess(int depth) 394 { 395 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 396 return; 397 } 398 int processNum = fork(); 399 if (processNum == 0) { 400 while (1) { 401 ApplyForRealloc(depth); 402 usleep(5000); // sleep 5000 us 403 } 404 } else { 405 hookPid_ = processNum; 406 } 407 } 408 Getdata(BufferSplitter & totalbuffer,std::vector<std::string> & hookVec,char delimiter)409 bool Getdata(BufferSplitter& totalbuffer, std::vector<std::string>& hookVec, char delimiter) 410 { 411 totalbuffer.NextWord(delimiter); 412 if (!totalbuffer.CurWord()) { 413 return false; 414 } 415 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 416 hookVec.push_back(curWord); 417 return true; 418 } 419 StartAndStopHook()420 void StartAndStopHook() 421 { 422 #ifdef COVERAGE_TEST 423 const int coverageSleepTime = 5; // sleep 5s 424 sleep(coverageSleepTime); 425 StartDaemonProcessArgs(); 426 sleep(coverageSleepTime); 427 #else 428 sleep(1); 429 StartDaemonProcessArgs(); 430 sleep(WAIT_TIME); 431 #endif 432 std::string cmd = "kill -36 " + std::to_string(hookPid_); 433 system(cmd.c_str()); 434 435 sleep(SLEEP_TIME); // 等待生成文本 436 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 437 system(cmdEnd.c_str()); 438 #ifdef COVERAGE_TEST 439 const int waitFlushTime = 5; // sleep 5s 440 sleep(waitFlushTime); 441 #else 442 sleep(WAIT_FLUSH); 443 #endif 444 StopProcess(hookPid_); 445 StopProcess(daemonPid_); 446 } 447 int daemonPid_ = -1; 448 int hookPid_ = -1; 449 int modeIndex_ = 0; 450 int unwindDepth_ = 0; 451 int statisticsInterval_ = 0; 452 int sampleInterval_ = 0; 453 int jsReport_ = 0; 454 int jsMaxDepth_ = 0; 455 int mallocFreeMatchingInterval_ = 0; 456 bool offlineSymbolization_ = false; 457 bool callframeCompress_ = false; 458 bool stringCompress_ = false; 459 bool rawString_ = false; 460 bool responseLibraryMode_ = false; 461 std::string outFile_ = ""; 462 std::string outFileType_ = ""; 463 std::string mode_[2] = {"dwarf", "fp"}; 464 std::vector<char*> command_; 465 }; 466 467 /** 468 * @tc.name: native hook 469 * @tc.desc: Test hook malloc normal process. 470 * @tc.type: FUNC 471 */ 472 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0080, Function | MediumTest | Level1) 473 { 474 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 475 unwindDepth_ = 30; 476 outFileType_ = "malloc_"; 477 modeIndex_ = i; // 0 is dwarf, 1 is fp mode 478 StartMallocProcess(); 479 StartAndStopHook(); 480 481 int32_t ret = ReadFile(outFile_); 482 ASSERT_NE(ret, -1); 483 484 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 485 std::vector<std::string> hookVec; 486 std::string addr = ""; 487 int depth = 0; 488 int addrPos = 3; 489 bool isFirstHook = true; 490 do { 491 char delimiter = ';'; 492 Getdata(totalbuffer, hookVec, delimiter); 493 494 if (hookVec[0] == "malloc" && !isFirstHook) { 495 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 496 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 497 } 498 delimiter = '\n'; 499 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 500 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 501 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); // 4: fifth hook data, default malloc size 502 503 addr = hookVec[addrPos]; 504 depth = 0; 505 } else if (hookVec[0] == "free" && !isFirstHook) { 506 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 507 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 508 } 509 delimiter = '\n'; 510 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 511 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 512 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 513 EXPECT_EQ(depth, DEFAULT_DEPTH); 514 515 isFirstHook = false; 516 addr = ""; 517 depth = 0; 518 } else { 519 depth++; 520 } 521 522 hookVec.clear(); 523 } while (totalbuffer.NextLine()); 524 } 525 } 526 527 /** 528 * @tc.name: native hook 529 * @tc.desc: Test hook calloc normal process. 530 * @tc.type: FUNC 531 */ 532 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0090, Function | MediumTest | Level3) 533 { 534 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 535 int setDepth = 1; 536 unwindDepth_ = 100; 537 outFileType_ = "calloc_"; 538 modeIndex_ = i; 539 StartCallocProcess(setDepth); 540 StartAndStopHook(); 541 542 int32_t ret = ReadFile(outFile_); 543 ASSERT_NE(ret, -1); 544 545 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 546 std::vector<std::string> hookVec; 547 std::string addr = ""; 548 int depth = 0; 549 int addrPos = 3; 550 bool isFirstHook = true; 551 do { 552 char delimiter = ';'; 553 Getdata(totalbuffer, hookVec, delimiter); 554 555 if (hookVec[0] == "malloc" && !isFirstHook) { 556 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 557 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 558 } 559 delimiter = '\n'; 560 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 561 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 562 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_CALLOC_SIZE); // 4: fifth hook data, default malloc size 563 564 addr = hookVec[addrPos]; 565 depth = 0; 566 } else if (hookVec[0] == "free" && !isFirstHook) { 567 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 568 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 569 } 570 delimiter = '\n'; 571 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 572 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 573 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 574 EXPECT_GE(depth, CALLOC_DEPTH); 575 576 isFirstHook = false; 577 addr = ""; 578 depth = 0; 579 } else { 580 depth++; 581 } 582 583 hookVec.clear(); 584 } while (totalbuffer.NextLine()); 585 } 586 } 587 588 /** 589 * @tc.name: native hook 590 * @tc.desc: Test hook realloc normal process. 591 * @tc.type: FUNC 592 */ 593 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0100, Function | MediumTest | Level3) 594 { 595 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 596 int setDepth = 100; 597 outFileType_ = "realloc_"; 598 modeIndex_ = i; 599 StartReallocProcess(setDepth); 600 StartAndStopHook(); 601 602 int32_t ret = ReadFile(outFile_); 603 ASSERT_NE(ret, -1); 604 605 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 606 std::vector<std::string> hookVec; 607 std::string mallocAddr = ""; 608 std::string reallocAddr = ""; 609 int depth = 0; 610 int addrPos = 3; 611 bool isFirstHook = true; 612 bool isRealloc = false; 613 do { 614 char delimiter = ';'; 615 Getdata(totalbuffer, hookVec, delimiter); 616 617 if (hookVec[0] == "malloc" && !isFirstHook) { 618 for (int i = 0; i < MALLOC_GET_DATE_SIZE; i++) { 619 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 620 } 621 delimiter = '\n'; 622 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 623 ASSERT_EQ(static_cast<int>(hookVec.size()), MALLOC_VEC_SIZE); 624 625 if (isRealloc) { 626 reallocAddr = hookVec[addrPos]; 627 // 4: fifth hook data, default malloc size 628 ASSERT_GE(atoi(hookVec[4].c_str()), DEFAULT_REALLOC_SIZE); 629 EXPECT_GE(depth, REALLOC_DEPTH); 630 isFirstHook = false; 631 } else { 632 mallocAddr = hookVec[addrPos]; 633 // 4: fifth hook data, default malloc size 634 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); 635 } 636 637 isRealloc = true; 638 depth = 0; 639 } else if (hookVec[0] == "free" && !isFirstHook) { 640 for (int i = 0; i < FREE_GET_DATA_SIZE; i++) { 641 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 642 } 643 delimiter = '\n'; 644 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 645 ASSERT_EQ(static_cast<int>(hookVec.size()), FREE_VEC_SIZE); 646 647 if (isRealloc) { 648 EXPECT_STREQ(hookVec[addrPos].c_str(), reallocAddr.c_str()); 649 reallocAddr = ""; 650 } else { 651 EXPECT_STREQ(hookVec[addrPos].c_str(), mallocAddr.c_str()); 652 mallocAddr = ""; 653 } 654 655 isRealloc = false; 656 depth = 0; 657 } else { 658 depth++; 659 } 660 661 hookVec.clear(); 662 } while (totalbuffer.NextLine()); 663 } 664 } 665 666 /** 667 * @tc.name: native hook 668 * @tc.desc: Test hook dlopen normal process. 669 * @tc.type: FUNC 670 */ 671 #ifdef __aarch64__ 672 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0110, Function | MediumTest | Level3) 673 { 674 for (size_t i = 1; i < 2; ++i) { 675 unwindDepth_ = 6; 676 outFileType_ = "dlopen_"; 677 modeIndex_ = i; 678 StartDlopenProcess(); 679 StartAndStopHook(); 680 std::ifstream infile; 681 infile.open(outFile_, std::ios::in); 682 EXPECT_TRUE(infile.is_open()); 683 std::string buf; 684 uint8_t mallocPos = 0; 685 uint8_t mallocSizePos = 6; 686 uint8_t libUnwindDepth = 3; 687 while (getline(infile, buf)) 688 { 689 std::vector<std::string>& resultVec = StringSplit(buf); 690 if (resultVec[mallocPos] == "malloc") { 691 if (resultVec[mallocSizePos] == std::to_string(LIBA_MALLOC_SIZE)) { 692 std::cout << buf << std::endl; 693 for (size_t i = 0; i < libUnwindDepth; i++) { 694 getline(infile, buf); 695 } 696 std::cout << buf << std::endl; 697 EXPECT_TRUE(buf.find("liba.z.so") != std::string::npos); 698 } else if (resultVec[mallocSizePos] == std::to_string(LIBB_MALLOC_SIZE)) { 699 std::cout << buf << std::endl; 700 for (size_t i = 0; i < libUnwindDepth; i++) { 701 getline(infile, buf); 702 } 703 std::cout << buf << std::endl; 704 EXPECT_TRUE(buf.find("libb.z.so") != std::string::npos); 705 } 706 } 707 } 708 } 709 } 710 #endif 711 712 /** 713 * @tc.name: native hook 714 * @tc.desc: Test hook statistics data normal process. 715 * @tc.type: FUNC 716 */ 717 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0120, Function | MediumTest | Level1) 718 { 719 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 720 unwindDepth_ = 10; 721 statisticsInterval_ = 1; 722 outFileType_ = "statistics_interval_"; 723 modeIndex_ = i; 724 StartMallocProcess(); 725 sleep(1); 726 StartDaemonProcessArgs(); 727 sleep(1); 728 std::string cmd = "kill -36 " + std::to_string(hookPid_); 729 system(cmd.c_str()); 730 731 sleep(SLEEP_TIME); // 等待生成文本 732 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 733 system(cmdEnd.c_str()); 734 sleep(WAIT_FLUSH); 735 StopProcess(hookPid_); 736 syscall(SYS_tkill, daemonPid_, 2); 737 738 std::ifstream infile; 739 infile.open(outFile_, std::ios::in); 740 EXPECT_TRUE(infile.is_open()); 741 std::string buf; 742 std::string expectCallStackId; 743 std::string statisticsCallStackId; 744 while (getline(infile, buf)) { 745 if (buf.find("stack_map") != std::string::npos) { 746 if (!expectCallStackId.empty()) { 747 continue; 748 } 749 getline(infile, buf); // read stack_map id 750 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 751 expectCallStackId = resultVec[1]; 752 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 753 } else if (buf.find("statistics_event") != std::string::npos) { 754 getline(infile, buf); // read statistics_event pid 755 getline(infile, buf); // read statistics_event callstack_id 756 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 757 statisticsCallStackId = resultVec[1]; 758 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 759 if (expectCallStackId == statisticsCallStackId) { 760 break; 761 } 762 } 763 } 764 getline(infile, buf); // read statistics_event apply_count 765 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 766 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 767 std::cout << "applyCount: " << applyCount << std::endl; 768 EXPECT_TRUE(applyCount > 0); 769 sleep(SLEEP_TIME); 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 sleep(SLEEP_TIME); 1040 } 1041 } 1042 1043 /** 1044 * @tc.name: native hook 1045 * @tc.desc: Test hook alloc free matching interval normal process. 1046 * @tc.type: FUNC 1047 */ 1048 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0190, Function | MediumTest | Level3) 1049 { 1050 for (size_t i = 0; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1051 unwindDepth_ = 6; 1052 outFileType_ = "mallocFreeMatchingInterval_"; 1053 modeIndex_ = i; 1054 mallocFreeMatchingInterval_ = 2; 1055 StartMallocProcess(); 1056 StartAndStopHook(); 1057 1058 std::ifstream infile; 1059 infile.open(outFile_, std::ios::in); 1060 EXPECT_TRUE(infile.is_open()); 1061 std::string buf; 1062 bool findSymbolName; 1063 bool findfilePath; 1064 bool findFrameMap; 1065 bool findStackMap; 1066 while (getline(infile, buf)) 1067 { 1068 if (!findSymbolName || buf.find("symbol_name") != std::string::npos) { 1069 findSymbolName = true; 1070 } else if (!findfilePath || buf.find("file_path") != std::string::npos) { 1071 findfilePath = true; 1072 } else if (!findFrameMap || buf.find("frame_map") != std::string::npos) { 1073 findFrameMap = true; 1074 } else if (!findStackMap || buf.find("stack_map") != std::string::npos) { 1075 findStackMap = true; 1076 if (findSymbolName && findfilePath && findFrameMap) { 1077 break; 1078 } 1079 } 1080 } 1081 EXPECT_TRUE(findSymbolName); 1082 EXPECT_TRUE(findfilePath); 1083 EXPECT_TRUE(findFrameMap); 1084 EXPECT_TRUE(findStackMap); 1085 } 1086 } 1087 1088 1089 /** 1090 * @tc.name: native hook 1091 * @tc.desc: Test hook js statistics data normal process. 1092 * @tc.type: FUNC 1093 */ 1094 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0200, Function | MediumTest | Level1) 1095 { 1096 for (size_t i = 1; i < 2; ++i) { // 2: 0 is dwarf, 1 is fp mode 1097 unwindDepth_ = 10; 1098 statisticsInterval_ = 1; 1099 jsReport_ = 1; 1100 jsMaxDepth_ = 10; 1101 outFileType_ = "js_report_"; 1102 modeIndex_ = i; 1103 StartMallocProcess(); 1104 sleep(1); 1105 StartDaemonProcessArgs(); 1106 sleep(1); 1107 std::string cmd = "kill -36 " + std::to_string(hookPid_); 1108 system(cmd.c_str()); 1109 1110 sleep(SLEEP_TIME); // 等待生成文本 1111 std::string cmdEnd = "kill -37 " + std::to_string(hookPid_); 1112 system(cmdEnd.c_str()); 1113 sleep(WAIT_FLUSH); 1114 StopProcess(hookPid_); 1115 syscall(SYS_tkill, daemonPid_, 2); 1116 1117 std::ifstream infile; 1118 infile.open(outFile_, std::ios::in); 1119 EXPECT_TRUE(infile.is_open()); 1120 std::string buf; 1121 std::string expectCallStackId; 1122 std::string statisticsCallStackId; 1123 while (getline(infile, buf)) { 1124 if (buf.find("stack_map") != std::string::npos) { 1125 if (!expectCallStackId.empty()) { 1126 continue; 1127 } 1128 getline(infile, buf); // read stack_map id 1129 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1130 expectCallStackId = resultVec[1]; 1131 std::cout << "expectCallStackId: " << expectCallStackId << std::endl; 1132 } else if (buf.find("statistics_event") != std::string::npos) { 1133 getline(infile, buf); // read statistics_event pid 1134 getline(infile, buf); // read statistics_event callstack_id 1135 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1136 statisticsCallStackId = resultVec[1]; 1137 std::cout << "statisticsCallStackId: " << statisticsCallStackId << std::endl; 1138 if (expectCallStackId == statisticsCallStackId) { 1139 break; 1140 } 1141 } 1142 } 1143 getline(infile, buf); // read statistics_event apply_count 1144 std::vector<std::string>& resultVec = StringSplit(buf, ':'); 1145 uint16_t applyCount = std::atoi(resultVec[1].c_str()); 1146 std::cout << "applyCount: " << applyCount << std::endl; 1147 EXPECT_TRUE(applyCount > 0); 1148 sleep(SLEEP_TIME); 1149 } 1150 } 1151 } 1152 1153 #pragma clang optimize on