• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. 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 <atomic>
17 #include <climits>
18 #include <dlfcn.h>
19 #include <fcntl.h>
20 #include <malloc.h>
21 #include <string>
22 #include <sys/time.h>
23 #include <pthread.h>
24 #include <sys/prctl.h>
25 #include <unordered_map>
26 #include <unordered_set>
27 #include "dfx_regs_get.h"
28 #include "common.h"
29 #include "hook_common.h"
30 #include "hook_socket_client.h"
31 #include "musl_preinit_common.h"
32 #include "parameter.h"
33 #include "stack_writer.h"
34 #include "runtime_stack_range.h"
35 #include "get_thread_id.h"
36 #include "hook_client.h"
37 #include <sys/mman.h>
38 #include "sampling.h"
39 
40 using namespace OHOS::HiviewDFX;
41 using namespace OHOS::Developtools::NativeDaemon;
42 
43 static pthread_key_t g_disableHookFlag;
44 static pthread_key_t g_hookTid;
45 static pthread_key_t g_updateThreadNameCount;
46 namespace {
47 static std::atomic<uint64_t> g_mallocTimes = 0;
48 
49 #ifdef PERFORMANCE_DEBUG
50 static std::atomic<uint64_t> g_timeCost = 0;
51 static std::atomic<uint64_t> g_dataCounts = 0;
52 constexpr int PRINT_INTERVAL = 5000;
53 constexpr uint64_t S_TO_NS = 1000 * 1000 * 1000;
54 #endif
55 
56 using OHOS::Developtools::NativeDaemon::buildArchType;
57 static std::shared_ptr<HookSocketClient> g_hookClient;
58 static Sampling g_sampler;
59 std::recursive_timed_mutex g_ClientMutex;
60 std::mutex g_tagMapMutex;
61 std::atomic<const MallocDispatchType*> g_dispatch {nullptr};
62 constexpr int UPDATE_THEARD_NAME = 1000;
63 static pid_t g_hookPid = 0;
64 static ClientConfig g_ClientConfig = {0};
65 static uint32_t g_maxSize = INT_MAX;
66 static std::unordered_map<std::string, uint32_t> g_memTagMap;
67 constexpr int PID_STR_SIZE = 4;
68 constexpr int STATUS_LINE_SIZE = 512;
69 constexpr int PID_NAMESPACE_ID = 1; // 1: pid is 1 after pid namespace used
70 constexpr int FD_PATH_LENGTH = 64;
71 constexpr int MIN_SAMPLER_INTERVAL = 1;
72 constexpr int FIRST_HASH = 16;
73 constexpr int SECOND_HASH = 13;
74 constexpr int THRESHOLD = 256;
75 constexpr int DIVIDE_VAL = 32;
76 //5: fp mode is used, response_library_mode maximum stack depth
77 #if defined(__aarch64__)
78 constexpr int RESPONSE_LIBRARY_MODE_DEPTH = 5;
79 #endif
80 static bool g_isPidChanged = false;
81 static struct mallinfo2 g_miStart = {0};
82 std::vector<std::pair<uint64_t, uint64_t>> g_filterStaLibRange;
83 constexpr int MAX_BITPOOL_SIZE = 100 * 1024;
84 struct Bitpool {
85     std::atomic<uint32_t> slot;
86 };
87 Bitpool g_addressChecker[MAX_BITPOOL_SIZE] = {{0}};
88 
AddrHash(uint32_t h)89 inline static uint32_t AddrHash(uint32_t h)
90 {
91     h ^= h >> FIRST_HASH;
92     h *= 0x85ebca6b;
93     h ^= h >> SECOND_HASH;
94     h *= 0xc2b2ae35;
95     h ^= h >> FIRST_HASH;
96     return h;
97 }
98 
Addr2Bitpool(void * addr)99 inline void Addr2Bitpool(void* addr)
100 {
101     uint32_t val = AddrHash(static_cast<uint32_t>(reinterpret_cast<uint64_t>(addr))) % (MAX_BITPOOL_SIZE * DIVIDE_VAL);
102     g_addressChecker[val / DIVIDE_VAL].slot |= (0x1 << (val % DIVIDE_VAL));
103 }
104 
IsAddrExist(void * addr)105 inline bool IsAddrExist(void* addr)
106 {
107     uint32_t val = AddrHash(static_cast<uint32_t>(reinterpret_cast<uint64_t>(addr))) % (MAX_BITPOOL_SIZE * DIVIDE_VAL);
108     if (g_addressChecker[val / DIVIDE_VAL].slot.load() & (0x1 << (val % DIVIDE_VAL))) {
109         return true;
110     }
111     return false;
112 }
113 
GetDispatch()114 const MallocDispatchType* GetDispatch()
115 {
116     return g_dispatch.load(std::memory_order_relaxed);
117 }
118 
InititalizeIPC()119 bool InititalizeIPC()
120 {
121     return true;
122 }
FinalizeIPC()123 void FinalizeIPC() {}
124 
ConvertPid(char * buf)125 int ConvertPid(char* buf)
126 {
127     int count = 0;
128     char pidBuf[11] = {0}; /* 11: 32 bits to the maximum length of a string */
129     char *str = buf;
130     while (*str != '\0') {
131         if ((*str >= '0') && (*str <= '9') && (static_cast<unsigned long>(count) < sizeof(pidBuf) - 1)) {
132             pidBuf[count] = *str;
133             count++;
134             str++;
135             continue;
136         }
137 
138         if (count > 0) {
139             break;
140         }
141         str++;
142     }
143     return atoi(pidBuf);
144 }
145 
GetRealPid(void)146 pid_t GetRealPid(void)
147 {
148     const char *path = "/proc/self/status";
149     char buf[STATUS_LINE_SIZE] = {0};
150     FILE *fp = fopen(path, "r");
151     CHECK_NOTNULL(fp, -1, "fopen fail");
152     while (!feof(fp)) {
153         if (fgets(buf, STATUS_LINE_SIZE, fp) == nullptr) {
154             fclose(fp);
155             return -1;
156         }
157         if (strncmp(buf, "Pid:", PID_STR_SIZE) == 0) {
158             break;
159         }
160     }
161     (void)fclose(fp);
162     return static_cast<pid_t>(ConvertPid(buf));
163 }
164 }  // namespace
165 
GetCurThreadId()166 pid_t inline __attribute__((always_inline)) GetCurThreadId()
167 {
168     if (pthread_getspecific(g_hookTid) == nullptr) {
169         pthread_setspecific(g_hookTid, reinterpret_cast<void *>(GetThreadId()));
170     }
171     return reinterpret_cast<long>((pthread_getspecific(g_hookTid)));
172 }
173 
UpdateThreadName(std::shared_ptr<HookSocketClient> & client)174 bool inline __attribute__((always_inline)) UpdateThreadName(std::shared_ptr<HookSocketClient>& client)
175 {
176     long updateCount = reinterpret_cast<long>(pthread_getspecific(g_updateThreadNameCount));
177     bool ret = true;
178     if (updateCount == 0) {
179         StackRawData tnameData = {{{{0}}}};
180         tnameData.tid = static_cast<uint32_t>(GetCurThreadId());
181         tnameData.type = THREAD_NAME_MSG;
182         prctl(PR_GET_NAME, tnameData.name);
183         ret = client->SendStackWithPayload(&tnameData,
184                                            sizeof(BaseStackRawData) + strlen(tnameData.name) + 1, nullptr, 0);
185         if (!ret) {
186             PROFILER_LOG_DEBUG(LOG_CORE, "Send thread name failed!");
187             return ret;
188         }
189     }
190     pthread_setspecific(g_updateThreadNameCount,
191                         reinterpret_cast<void *>(updateCount == UPDATE_THEARD_NAME ? 0 : updateCount + 1));
192     return ret;
193 }
194 
GetTagId(std::shared_ptr<HookSocketClient> & client,const char * tagName)195 uint32_t inline __attribute__((always_inline)) GetTagId(std::shared_ptr<HookSocketClient>& client, const char* tagName)
196 {
197     if (tagName == nullptr) {
198         return 0;
199     }
200     uint32_t tagId = 0;
201     bool isNewTag = false;
202     std::unique_lock<std::mutex> lock(g_tagMapMutex);
203     auto it = g_memTagMap.find(tagName);
204     if (it == g_memTagMap.end()) {
205         isNewTag = true;
206         tagId = g_memTagMap.size() + 1;
207         g_memTagMap[tagName] = tagId;
208     } else {
209         tagId = it->second;
210     }
211     lock.unlock();
212     if (isNewTag) {
213         StackRawData tagData = {{{{0}}}};
214         tagData.type = MEMORY_TAG;
215         tagData.tagId = tagId;
216         if (strcpy_s(tagData.name, PATH_MAX + 1, tagName) != 0) {
217             PROFILER_LOG_ERROR(LOG_CORE, "Set tag name failed");
218         }
219         if (client != nullptr) {
220             client->SendStackWithPayload(&tagData, sizeof(BaseStackRawData) + strlen(tagName) + 1, nullptr, 0);
221         }
222     }
223     return tagId;
224 }
225 
226 static bool IsPidChanged(void);
227 
ohos_malloc_hook_on_start(void (* disableHookCallback)())228 bool ohos_malloc_hook_on_start(void (*disableHookCallback)())
229 {
230     std::lock_guard<std::recursive_timed_mutex> guard(g_ClientMutex);
231     g_miStart = mallinfo2();
232     COMMON::PrintMallinfoLog("before hook(byte) => ", g_miStart);
233     g_hookPid = GetRealPid();
234     g_mallocTimes = 0;
235     if (g_hookClient != nullptr) {
236         PROFILER_LOG_INFO(LOG_CORE, "hook already started");
237         return true;
238     } else {
239         g_ClientConfig.Reset();
240         g_sampler.Reset();
241         g_hookClient = std::make_shared<HookSocketClient>(g_hookPid, &g_ClientConfig, &g_sampler, disableHookCallback);
242     }
243     pthread_key_create(&g_disableHookFlag, nullptr);
244     pthread_setspecific(g_disableHookFlag, nullptr);
245     pthread_key_create(&g_hookTid, nullptr);
246     pthread_setspecific(g_hookTid, nullptr);
247     pthread_key_create(&g_updateThreadNameCount, nullptr);
248     pthread_setspecific(g_updateThreadNameCount, reinterpret_cast<void *>(0));
249     PROFILER_LOG_INFO(LOG_CORE, "ohos_malloc_hook_on_start");
250     GetMainThreadRuntimeStackRange(g_filterStaLibRange);
251     constexpr int paramBufferLen = 128;
252     char paramOutBuf[paramBufferLen] = {0};
253     int ret = GetParameter("persist.hiviewdfx.profiler.mem.filter", "", paramOutBuf, paramBufferLen);
254     if (ret > 0) {
255         int min = 0;
256         int max = 0;
257         if (sscanf_s(paramOutBuf, "%d,%d", &min, &max) == 2) { // 2: two parameters.
258             g_maxSize = max > 0 ? max : INT_MAX;
259             g_ClientConfig.filterSize = min > 0 ? min : 0;
260         }
261         PROFILER_LOG_INFO(LOG_CORE, "persist.hiviewdfx.profiler.mem.filter %s, min %d, max %d",
262                           paramOutBuf, g_ClientConfig.filterSize, g_maxSize);
263     }
264     return true;
265 }
266 
ohos_release_on_end(void *)267 void* ohos_release_on_end(void*)
268 {
269     std::lock_guard<std::recursive_timed_mutex> guard(g_ClientMutex);
270     g_hookClient = nullptr;
271     pthread_key_delete(g_disableHookFlag);
272     pthread_key_delete(g_hookTid);
273     pthread_key_delete(g_updateThreadNameCount);
274     g_ClientConfig.Reset();
275     PROFILER_LOG_INFO(LOG_CORE, "ohos_malloc_hook_on_end, mallocTimes :%" PRIu64, g_mallocTimes.load());
276     COMMON::PrintMallinfoLog("before hook(byte) => ", g_miStart);
277     struct mallinfo2 miFinal = mallinfo2();
278     COMMON::PrintMallinfoLog("after hook(byte) => ", miFinal);
279     return nullptr;
280 }
281 
ohos_malloc_hook_on_end(void)282 bool ohos_malloc_hook_on_end(void)
283 {
284     if (g_hookClient != nullptr) {
285         g_hookClient->Flush();
286     }
287     pthread_t threadEnd;
288     if (pthread_create(&threadEnd, nullptr, ohos_release_on_end, nullptr)) {
289         PROFILER_LOG_INFO(LOG_CORE, "create ohos_release_on_end fail");
290         return false;
291     }
292     pthread_detach(threadEnd);
293     return true;
294 }
295 
FilterStandardSoIp(uint64_t ip)296 bool FilterStandardSoIp(uint64_t ip)
297 {
298     for (auto [soBegin, soEnd_]: g_filterStaLibRange) {
299         if (ip >= soBegin && ip < soEnd_) {
300             return true;
301         }
302     }
303     return false;
304 }
305 
306 #if defined(__aarch64__)
FpUnwind(int maxDepth,uint64_t * ip,int stackSize)307 static int inline __attribute__((always_inline)) FpUnwind(int maxDepth, uint64_t *ip, int stackSize)
308 {
309     void **startfp = (void **)__builtin_frame_address(0);
310     void **fp = startfp;
311     int depth = 0;
312     int count = 0;
313     uint64_t tempIp = 0;
314     while (depth < maxDepth) {
315         void **nextFp = (void **)*fp;
316         if (nextFp <= fp) {
317             break;
318         }
319         if (((nextFp - startfp) * sizeof(void *)) > static_cast<unsigned long>(stackSize)) {
320             break;
321         }
322         fp = nextFp;
323         tempIp = *(reinterpret_cast<unsigned long *>(fp + 1));
324         if (tempIp == 0) {
325             break;
326         }
327         if (g_ClientConfig.responseLibraryMode) {
328             if (++count >= RESPONSE_LIBRARY_MODE_DEPTH || !FilterStandardSoIp(tempIp)) {
329                 break;
330             }
331         } else {
332             ip[depth++] = tempIp;
333         }
334     }
335     if (g_ClientConfig.responseLibraryMode) {
336         ip[0] = tempIp;
337         depth = 1;
338     }
339     return depth;
340 }
341 #endif
342 
hook_malloc(void * (* fn)(size_t),size_t size)343 void* hook_malloc(void* (*fn)(size_t), size_t size)
344 {
345     void* ret = nullptr;
346     if (fn) {
347         ret = fn(size);
348     }
349     if (g_ClientConfig.mallocDisable || IsPidChanged()) {
350         return ret;
351     }
352     if (!ohos_set_filter_size(size, ret)) {
353         return ret;
354     }
355     if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size) == 0) {  //0 not sampling
356         return ret;
357     }
358 #ifdef PERFORMANCE_DEBUG
359     struct timespec start = {};
360     clock_gettime(CLOCK_REALTIME, &start);
361 #endif
362     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
363     auto holder = weakClient.lock();
364     if (holder == nullptr) {
365         return ret;
366     }
367     if (!UpdateThreadName(holder)) {
368         return ret;
369     }
370     StackRawData rawdata = {{{{0}}}};
371     const char* stackptr = nullptr;
372     const char* stackendptr = nullptr;
373     int stackSize = 0;
374     int fpStackDepth = 0;
375     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
376 
377     if (g_ClientConfig.fpunwind) {
378 #ifdef __aarch64__
379         stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
380         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
381         stackSize = stackendptr - stackptr;
382         fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
383         stackSize = 0;
384 #endif
385     } else {
386         unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
387         GetLocalRegs(regs);
388         stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
389         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
390         stackSize = stackendptr - stackptr;
391     }
392     rawdata.type = MALLOC_MSG;
393     rawdata.pid = static_cast<uint32_t>(g_hookPid);
394     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
395     rawdata.mallocSize = size;
396     rawdata.addr = ret;
397     if (g_ClientConfig.sampleInterval >= THRESHOLD) {
398         Addr2Bitpool(ret);
399     }
400     int realSize = 0;
401     if (g_ClientConfig.fpunwind) {
402         realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
403     } else {
404         realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
405     }
406     holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
407     g_mallocTimes++;
408 #ifdef PERFORMANCE_DEBUG
409     struct timespec end = {};
410     clock_gettime(CLOCK_REALTIME, &end);
411     g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
412     g_dataCounts += stackSize;
413     if (g_mallocTimes % PRINT_INTERVAL == 0) {
414         PROFILER_LOG_ERROR(LOG_CORE,
415             "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
416             g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
417     }
418 #endif
419     return ret;
420 }
421 
hook_valloc(void * (* fn)(size_t),size_t size)422 void* hook_valloc(void* (*fn)(size_t), size_t size)
423 {
424     void* pRet = nullptr;
425     if (fn) {
426         pRet = fn(size);
427     }
428     return pRet;
429 }
430 
hook_calloc(void * (* fn)(size_t,size_t),size_t number,size_t size)431 void* hook_calloc(void* (*fn)(size_t, size_t), size_t number, size_t size)
432 {
433     void* pRet = nullptr;
434     if (fn) {
435         pRet = fn(number, size);
436     }
437     if (g_ClientConfig.mallocDisable || IsPidChanged()) {
438         return pRet;
439     }
440     if (!ohos_set_filter_size(number * size, pRet)) {
441         return pRet;
442     }
443     if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size * number) == 0) {
444         return pRet;
445     }
446     StackRawData rawdata = {{{{0}}}};
447     const char* stackptr = nullptr;
448     const char* stackendptr = nullptr;
449     int stackSize = 0;
450     int fpStackDepth = 0;
451     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
452 
453     if (g_ClientConfig.fpunwind) {
454 #ifdef __aarch64__
455         stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
456         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
457         stackSize = stackendptr - stackptr;
458         fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
459         stackSize = 0;
460 #endif
461     } else {
462         unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
463         GetLocalRegs(regs);
464         stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
465         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
466         stackSize = stackendptr - stackptr;
467     }
468 
469     rawdata.type = MALLOC_MSG;
470     rawdata.pid = static_cast<uint32_t>(g_hookPid);
471     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
472     rawdata.mallocSize = number * size;
473     rawdata.addr = pRet;
474     if (g_ClientConfig.sampleInterval >= THRESHOLD) {
475         Addr2Bitpool(pRet);
476     }
477     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
478     auto holder = weakClient.lock();
479     if (holder != nullptr) {
480         int realSize = 0;
481         if (g_ClientConfig.fpunwind) {
482             realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
483         } else {
484             realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
485         }
486         holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
487     }
488     g_mallocTimes++;
489     return pRet;
490 }
491 
hook_memalign(void * (* fn)(size_t,size_t),size_t align,size_t bytes)492 void* hook_memalign(void* (*fn)(size_t, size_t), size_t align, size_t bytes)
493 {
494     void* pRet = nullptr;
495     if (fn) {
496         pRet = fn(align, bytes);
497     }
498     return pRet;
499 }
500 
hook_realloc(void * (* fn)(void *,size_t),void * ptr,size_t size)501 void* hook_realloc(void* (*fn)(void*, size_t), void* ptr, size_t size)
502 {
503     void* pRet = nullptr;
504     if (fn) {
505         pRet = fn(ptr, size);
506     }
507     if (g_ClientConfig.mallocDisable || IsPidChanged()) {
508         return pRet;
509     }
510     if (!ohos_set_filter_size(size, pRet)) {
511         return pRet;
512     }
513     if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size) == 0) {
514         return pRet;
515     }
516     StackRawData rawdata = {{{{0}}}};
517     StackRawData freeData = {{{{0}}}};
518     const char* stackptr = nullptr;
519     const char* stackendptr = nullptr;
520     int stackSize = 0;
521     int fpStackDepth = 0;
522     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
523 
524     if (g_ClientConfig.fpunwind) {
525 #ifdef __aarch64__
526         stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
527         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
528         stackSize = stackendptr - stackptr;
529         fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
530         stackSize = 0;
531         if (g_ClientConfig.freeStackData) {
532             (void)memcpy_s(freeData.ip, sizeof(freeData.ip) / sizeof(uint64_t),
533                            rawdata.ip, sizeof(rawdata.ip) / sizeof(uint64_t));
534         }
535 #endif
536     } else {
537         unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
538         GetLocalRegs(regs);
539         stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
540         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
541         stackSize = stackendptr - stackptr;
542         if (g_ClientConfig.freeStackData) {
543             (void)memcpy_s(freeData.regs, sizeof(freeData.regs) / sizeof(char),
544                            rawdata.regs, sizeof(rawdata.regs) / sizeof(char));
545         }
546     }
547 
548     rawdata.type = MALLOC_MSG;
549     rawdata.pid = static_cast<uint32_t>(g_hookPid);
550     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
551     rawdata.mallocSize = size;
552     rawdata.addr = pRet;
553     if (g_ClientConfig.sampleInterval >= THRESHOLD) {
554         Addr2Bitpool(pRet);
555     }
556     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
557     auto holder = weakClient.lock();
558     if (holder != nullptr) {
559         int realSize = 0;
560         freeData.type = FREE_MSG;
561         freeData.pid = rawdata.pid;
562         freeData.tid = rawdata.tid;
563         freeData.mallocSize = 0;
564         freeData.addr = ptr;
565         freeData.ts = rawdata.ts;
566         if (g_ClientConfig.fpunwind) {
567             realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
568         } else {
569             realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
570         }
571         holder->SendStackWithPayload(&freeData, sizeof(BaseStackRawData), nullptr, 0); // 0: Don't unwind the freeData
572         holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
573     }
574     return pRet;
575 }
576 
hook_malloc_usable_size(size_t (* fn)(void *),void * ptr)577 size_t hook_malloc_usable_size(size_t (*fn)(void*), void* ptr)
578 {
579     size_t ret = 0;
580     if (fn) {
581         ret = fn(ptr);
582     }
583 
584     return ret;
585 }
586 
hook_free(void (* free_func)(void *),void * p)587 void hook_free(void (*free_func)(void*), void* p)
588 {
589     if (free_func) {
590         free_func(p);
591     }
592     if (g_ClientConfig.mallocDisable || IsPidChanged()) {
593         return;
594     }
595     if (g_ClientConfig.sampleInterval >= THRESHOLD) {
596         if (!IsAddrExist(p)) {
597             return;
598         }
599     }
600     if (g_ClientConfig.freeEventOnlyAddrEnable) {
601         uint64_t addr = reinterpret_cast<uint64_t>(p);
602         std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
603         auto holder = weakClient.lock();
604         if (holder != nullptr) {
605             holder->SendStackWithPayload(&addr, sizeof(addr), nullptr, 0);
606         }
607         return;
608     }
609     StackRawData rawdata = {{{{0}}}};
610     const char* stackptr = nullptr;
611     const char* stackendptr = nullptr;
612     int stackSize = 0;
613     int fpStackDepth = 0;
614     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
615 
616     if (g_ClientConfig.freeStackData) {
617         if (g_ClientConfig.fpunwind) {
618 #ifdef __aarch64__
619             stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
620             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
621             stackSize = stackendptr - stackptr;
622             fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
623             stackSize = 0;
624 #endif
625         } else {
626             unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
627             GetLocalRegs(regs);
628             stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
629             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
630             stackSize = stackendptr - stackptr;
631         }
632     }
633 
634     rawdata.type = FREE_MSG;
635     rawdata.pid = static_cast<uint32_t>(g_hookPid);
636     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
637     rawdata.mallocSize = 0;
638     rawdata.addr = p;
639     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
640     auto holder = weakClient.lock();
641     if (holder != nullptr) {
642         int realSize = 0;
643         if (g_ClientConfig.fpunwind) {
644             realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
645         } else {
646             realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
647         }
648         holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
649     }
650 }
651 
SendMmapFileRawData(int prot,int flags,off_t offset,const std::string & filePath,const StackRawData & rawdata,std::shared_ptr<HookSocketClient> & holder)652 inline void SendMmapFileRawData(int prot, int flags, off_t offset, const std::string& filePath,
653                                 const StackRawData& rawdata, std::shared_ptr<HookSocketClient>& holder)
654 {
655     StackRawData curRawdata = {{{{0}}}};
656     curRawdata.addr = rawdata.addr;
657     curRawdata.pid = static_cast<uint32_t>(g_hookPid);
658     curRawdata.mallocSize = rawdata.mallocSize;
659     curRawdata.mmapArgs.offset = offset;
660     curRawdata.type = OHOS::Developtools::NativeDaemon::MMAP_FILE_TYPE;
661     if (prot & PROT_EXEC) {
662         curRawdata.mmapArgs.flags |= PROT_EXEC;
663     }
664     if (flags & MAP_FIXED) {
665         curRawdata.mmapArgs.flags |= MAP_FIXED;
666         curRawdata.name[0] = '\0';
667         holder->SendStackWithPayload(&curRawdata, sizeof(BaseStackRawData) + 1, nullptr, 0);
668     } else {
669         size_t len = strlen(filePath.c_str()) + 1;
670         (void)strncpy_s(curRawdata.name, PATH_MAX + 1, filePath.c_str(), len);
671         holder->SendStackWithPayload(&curRawdata, sizeof(BaseStackRawData) + len, nullptr, 0);
672     }
673 }
674 
hook_mmap(void * (* fn)(void *,size_t,int,int,int,off_t),void * addr,size_t length,int prot,int flags,int fd,off_t offset)675 void* hook_mmap(void*(*fn)(void*, size_t, int, int, int, off_t),
676     void* addr, size_t length, int prot, int flags, int fd, off_t offset)
677 {
678     void* ret = nullptr;
679     if (fn) {
680         ret = fn(addr, length, prot, flags, fd, offset);
681     }
682     if (g_ClientConfig.mmapDisable || IsPidChanged()) {
683         return ret;
684     }
685     if ((fd < 0 && offset == 0) && g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL
686         && g_sampler.StartSampling(length) == 0) {
687         return ret;
688     }
689     StackRawData rawdata = {{{{0}}}};
690     const char* stackptr = nullptr;
691     const char* stackendptr = nullptr;
692     int stackSize = 0;
693     int fpStackDepth = 0;
694     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
695 
696     if (g_ClientConfig.fpunwind) {
697 #ifdef __aarch64__
698         stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
699         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
700         stackSize = stackendptr - stackptr;
701         fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
702         stackSize = 0;
703 #endif
704     } else {
705         unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
706         GetLocalRegs(regs);
707         stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
708         GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
709         stackSize = stackendptr - stackptr;
710     }
711 
712     rawdata.type = MMAP_MSG;
713     rawdata.pid = static_cast<uint32_t>(g_hookPid);
714     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
715     rawdata.mallocSize = length;
716     rawdata.addr = ret;
717     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
718     auto holder = weakClient.lock();
719     if (holder == nullptr) {
720         return ret;
721     }
722     if (fd >= 0) {
723         rawdata.type = MMAP_FILE_PAGE_MSG;
724         char path[FD_PATH_LENGTH] = {0};
725         char fileName[PATH_MAX + 1] = {0};
726         (void)snprintf_s(path, FD_PATH_LENGTH, FD_PATH_LENGTH - 1, "/proc/self/fd/%d", fd);
727         ssize_t len = readlink(path, fileName, sizeof(fileName) - 1);
728         if (len != -1) {
729             fileName[len] = '\0';
730             SendMmapFileRawData(prot, flags, offset, fileName, rawdata, holder);
731             char* p = strrchr(fileName, '/');
732             if (p != nullptr) {
733                 rawdata.tagId = GetTagId(holder, &fileName[p - fileName + 1]);
734             } else {
735                 rawdata.tagId = GetTagId(holder, fileName);
736             }
737         } else {
738             PROFILER_LOG_ERROR(LOG_CORE, "Set mmap fd linked file name failed!");
739         }
740     }
741     if (!UpdateThreadName(holder)) {
742         return ret;
743     }
744     int realSize = 0;
745     if (g_ClientConfig.fpunwind) {
746         realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
747     } else {
748         realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
749     }
750     holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
751     return ret;
752 }
753 
hook_munmap(int (* fn)(void *,size_t),void * addr,size_t length)754 int hook_munmap(int(*fn)(void*, size_t), void* addr, size_t length)
755 {
756     int ret = -1;
757     if (fn) {
758         ret = fn(addr, length);
759     }
760     if (g_ClientConfig.mmapDisable || IsPidChanged()) {
761         return ret;
762     }
763     int stackSize = 0;
764     StackRawData rawdata = {{{{0}}}};
765     const char* stackptr = nullptr;
766     const char* stackendptr = nullptr;
767     int fpStackDepth = 0;
768     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
769 
770     if (g_ClientConfig.munmapStackData) {
771         if (g_ClientConfig.fpunwind) {
772 #ifdef __aarch64__
773             stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
774             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
775             stackSize = stackendptr - stackptr;
776             fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
777             stackSize = 0;
778 #endif
779         } else {
780             unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
781             GetLocalRegs(regs);
782             stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
783             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
784             stackSize = stackendptr - stackptr;
785         }
786     }
787 
788     rawdata.type = MUNMAP_MSG;
789     rawdata.pid = static_cast<uint32_t>(g_hookPid);
790     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
791     rawdata.mallocSize = length;
792     rawdata.addr = addr;
793     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
794     auto holder = weakClient.lock();
795     if (holder != nullptr) {
796         int realSize = 0;
797         if (g_ClientConfig.fpunwind) {
798             realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
799         } else {
800             realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
801         }
802         holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
803     }
804     return ret;
805 }
806 
hook_prctl(int (* fn)(int,...),int option,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)807 int hook_prctl(int(*fn)(int, ...),
808     int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
809 {
810     int ret = -1;
811     if (fn) {
812         ret = fn(option, arg2, arg3, arg4, arg5);
813     }
814     if (reinterpret_cast<char*>(arg5) == nullptr || IsPidChanged()) {
815         return ret;
816     }
817     if (option == PR_SET_VMA && arg2 == PR_SET_VMA_ANON_NAME) {
818         StackRawData rawdata = {{{{0}}}};
819         clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
820         rawdata.type = PR_SET_VMA_MSG;
821         rawdata.pid = static_cast<uint32_t>(g_hookPid);
822         rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
823         rawdata.mallocSize = arg4;
824         rawdata.addr = reinterpret_cast<void*>(arg3);
825 
826         std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
827         auto holder = weakClient.lock();
828         if (strcpy_s(rawdata.name, PATH_MAX + 1, reinterpret_cast<char*>(arg5))) {
829             PROFILER_LOG_ERROR(LOG_CORE, "Set tag name failed");
830         }
831         if (holder != nullptr) {
832             holder->SendStackWithPayload(&rawdata,
833                                          sizeof(rawdata) + strlen(reinterpret_cast<char*>(arg5)), nullptr, 0);
834         }
835     }
836     return ret;
837 }
838 
hook_memtrace(void * addr,size_t size,const char * tag,bool isUsing)839 void hook_memtrace(void* addr, size_t size, const char* tag, bool isUsing)
840 {
841     if (!g_ClientConfig.memtraceEnable || IsPidChanged()) {
842         return;
843     }
844     int stackSize = 0;
845     StackRawData rawdata = {{{{0}}}};
846     const char* stackptr = nullptr;
847     const char* stackendptr = nullptr;
848     int fpStackDepth = 0;
849     clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
850 
851     if (isUsing) {
852         if (g_ClientConfig.fpunwind) {
853 #ifdef __aarch64__
854             stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
855             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
856             stackSize = stackendptr - stackptr;
857             fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize);
858             stackSize = 0;
859 #endif
860         } else {
861             unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
862             GetLocalRegs(regs);
863             stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
864             GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId());  // stack end pointer
865             stackSize = stackendptr - stackptr;
866         }
867     }
868     rawdata.type = isUsing ? MEMORY_USING_MSG : MEMORY_UNUSING_MSG;
869     rawdata.pid = static_cast<uint32_t>(g_hookPid);
870     rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
871     rawdata.mallocSize = size;
872     rawdata.addr = addr;
873     std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
874     auto holder = weakClient.lock();
875     rawdata.tagId = isUsing ? GetTagId(holder, tag) : 0;
876     if (holder != nullptr) {
877         int realSize = 0;
878         if (g_ClientConfig.fpunwind) {
879             realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
880         } else {
881             realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
882         }
883         holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
884     }
885 }
886 
ohos_malloc_hook_initialize(const MallocDispatchType * malloc_dispatch,bool *,const char *)887 bool ohos_malloc_hook_initialize(const MallocDispatchType*malloc_dispatch, bool*, const char*)
888 {
889     g_dispatch.store(malloc_dispatch);
890     InititalizeIPC();
891     return true;
892 }
ohos_malloc_hook_finalize(void)893 void ohos_malloc_hook_finalize(void)
894 {
895     FinalizeIPC();
896 }
897 
ohos_malloc_hook_malloc(size_t size)898 void* ohos_malloc_hook_malloc(size_t size)
899 {
900     __set_hook_flag(false);
901     void* ret = hook_malloc(GetDispatch()->malloc, size);
902     __set_hook_flag(true);
903     return ret;
904 }
905 
ohos_malloc_hook_realloc(void * ptr,size_t size)906 void* ohos_malloc_hook_realloc(void* ptr, size_t size)
907 {
908     __set_hook_flag(false);
909     void* ret = hook_realloc(GetDispatch()->realloc, ptr, size);
910     __set_hook_flag(true);
911     return ret;
912 }
913 
ohos_malloc_hook_calloc(size_t number,size_t size)914 void* ohos_malloc_hook_calloc(size_t number, size_t size)
915 {
916     __set_hook_flag(false);
917     void* ret = hook_calloc(GetDispatch()->calloc, number, size);
918     __set_hook_flag(true);
919     return ret;
920 }
921 
ohos_malloc_hook_valloc(size_t size)922 void* ohos_malloc_hook_valloc(size_t size)
923 {
924     __set_hook_flag(false);
925     void* ret = hook_valloc(GetDispatch()->valloc, size);
926     __set_hook_flag(true);
927     return ret;
928 }
929 
ohos_malloc_hook_free(void * p)930 void ohos_malloc_hook_free(void* p)
931 {
932     __set_hook_flag(false);
933     hook_free(GetDispatch()->free, p);
934     __set_hook_flag(true);
935 }
936 
ohos_malloc_hook_memalign(size_t alignment,size_t bytes)937 void* ohos_malloc_hook_memalign(size_t alignment, size_t bytes)
938 {
939     __set_hook_flag(false);
940     void* ret = hook_memalign(GetDispatch()->memalign, alignment, bytes);
941     __set_hook_flag(true);
942     return ret;
943 }
944 
ohos_malloc_hook_malloc_usable_size(void * mem)945 size_t ohos_malloc_hook_malloc_usable_size(void* mem)
946 {
947     __set_hook_flag(false);
948     size_t ret = hook_malloc_usable_size(GetDispatch()->malloc_usable_size, mem);
949     __set_hook_flag(true);
950     return ret;
951 }
952 
ohos_malloc_hook_get_hook_flag(void)953 bool ohos_malloc_hook_get_hook_flag(void)
954 {
955     return pthread_getspecific(g_disableHookFlag) == nullptr;
956 }
957 
ohos_malloc_hook_set_hook_flag(bool flag)958 bool ohos_malloc_hook_set_hook_flag(bool flag)
959 {
960     bool oldFlag = ohos_malloc_hook_get_hook_flag();
961     if (flag) {
962         pthread_setspecific(g_disableHookFlag, nullptr);
963     } else {
964         pthread_setspecific(g_disableHookFlag, reinterpret_cast<void *>(1));
965     }
966     return oldFlag;
967 }
968 
ohos_malloc_hook_mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)969 void* ohos_malloc_hook_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
970 {
971     __set_hook_flag(false);
972     void* ret = hook_mmap(GetDispatch()->mmap, addr, length, prot, flags, fd, offset);
973     __set_hook_flag(true);
974     return ret;
975 }
976 
ohos_malloc_hook_munmap(void * addr,size_t length)977 int ohos_malloc_hook_munmap(void* addr, size_t length)
978 {
979     __set_hook_flag(false);
980     int ret = hook_munmap(GetDispatch()->munmap, addr, length);
981     __set_hook_flag(true);
982     return ret;
983 }
984 
ohos_malloc_hook_memtrace(void * addr,size_t size,const char * tag,bool isUsing)985 void ohos_malloc_hook_memtrace(void* addr, size_t size, const char* tag, bool isUsing)
986 {
987     __set_hook_flag(false);
988     hook_memtrace(addr, size, tag, isUsing);
989     __set_hook_flag(true);
990 }
991 
ohos_malloc_hook_prctl(int option,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)992 int  ohos_malloc_hook_prctl(int option, unsigned long arg2, unsigned long arg3,
993                             unsigned long arg4, unsigned long arg5)
994 {
995     __set_hook_flag(false);
996     int ret = hook_prctl((GetDispatch()->prctl), option, arg2, arg3, arg4, arg5);
997     __set_hook_flag(true);
998     return ret;
999 }
1000 
ohos_set_filter_size(size_t size,void * ret)1001 bool ohos_set_filter_size(size_t size, void* ret)
1002 {
1003     if (g_ClientConfig.filterSize < 0 || size < static_cast<size_t>(g_ClientConfig.filterSize) || size > g_maxSize) {
1004         return false;
1005     }
1006     return true;
1007 }
1008 
IsPidChanged(void)1009 static bool IsPidChanged(void)
1010 {
1011     if (g_isPidChanged) {
1012         return true;
1013     }
1014     int pid = getpid();
1015     // hap app after pid namespace used
1016     if (pid == PID_NAMESPACE_ID) {
1017         return false;
1018     } else {
1019         // native app & sa service
1020         g_isPidChanged = (g_hookPid != pid);
1021     }
1022     return g_isPidChanged;
1023 }