• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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