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