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