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 "c/executor_task.h"
29 #include "common.h"
30 #include "hook_common.h"
31 #include "hook_socket_client.h"
32 #include "musl_preinit_common.h"
33 #include "parameter.h"
34 #include "stack_writer.h"
35 #include "runtime_stack_range.h"
36 #include "get_thread_id.h"
37 #include "hook_client.h"
38 #include <sys/mman.h>
39 #include "sampling.h"
40 #include "hitrace/trace.h"
41
42 using namespace OHOS::HiviewDFX;
43 using namespace OHOS::Developtools::NativeDaemon;
44
45 static pthread_key_t g_disableHookFlag;
46 static pthread_key_t g_hookTid;
47 static pthread_key_t g_updateThreadNameCount;
48 namespace {
49 static std::atomic<uint64_t> g_mallocTimes = 0;
50
51 enum class MISC_TYPE : uint32_t {
52 JS_STACK_DATA = 1,
53 };
54
55 #ifdef PERFORMANCE_DEBUG
56 static std::atomic<uint64_t> g_timeCost = 0;
57 static std::atomic<uint64_t> g_dataCounts = 0;
58 constexpr int PRINT_INTERVAL = 5000;
59 constexpr uint64_t S_TO_NS = 1000 * 1000 * 1000;
60 #endif
61
62 using OHOS::Developtools::NativeDaemon::buildArchType;
63 static std::shared_ptr<HookSocketClient> g_hookClient {nullptr};
64 static Sampling g_sampler;
65 std::recursive_timed_mutex g_ClientMutex;
66 std::mutex g_tagMapMutex;
67 std::atomic<const MallocDispatchType*> g_dispatch {nullptr};
68 constexpr int UPDATE_THEARD_NAME = 1000;
69 static pid_t g_hookPid = 0;
70 static ClientConfig g_ClientConfig = {0};
71 static uint32_t g_maxSize = INT_MAX;
72 static std::unordered_map<std::string, uint32_t> g_memTagMap;
73 constexpr int PID_STR_SIZE = 4;
74 constexpr int STATUS_LINE_SIZE = 512;
75 constexpr int PID_NAMESPACE_ID = 1; // 1: pid is 1 after pid namespace used
76 constexpr int FD_PATH_LENGTH = 64;
77 constexpr int MIN_SAMPLER_INTERVAL = 1;
78 constexpr int FIRST_HASH = 16;
79 constexpr int SECOND_HASH = 13;
80 constexpr int THRESHOLD = 256;
81 constexpr int DIVIDE_VAL = 64;
82 //5: fp mode is used, response_library_mode maximum stack depth
83 #if defined(__aarch64__)
84 constexpr int RESPONSE_LIBRARY_MODE_DEPTH = 5;
85 constexpr int TEMP_IP = 100;
86 #endif
87 static bool g_isPidChanged = false;
88 static struct mallinfo2 g_miStart = {0};
89 std::vector<std::pair<uint64_t, uint64_t>> g_filterStaLibRange;
90 constexpr int MAX_BITPOOL_SIZE = 1000 * 1024;
91 struct Bitpool {
92 std::atomic<uint64_t> slot;
93 };
94 Bitpool* g_addressChecker = nullptr;
95
AddrHash(uint32_t h)96 inline static uint32_t AddrHash(uint32_t h)
97 {
98 h ^= h >> FIRST_HASH;
99 h *= 0x85ebca6b;
100 h ^= h >> SECOND_HASH;
101 h *= 0xc2b2ae35;
102 h ^= h >> FIRST_HASH;
103 return h;
104 }
105
Addr2Bitpool(void * addr)106 inline void Addr2Bitpool(void* addr)
107 {
108 if (!g_addressChecker) {
109 return;
110 }
111 uint32_t val = AddrHash(static_cast<uint32_t>(reinterpret_cast<uint64_t>(addr))) % (MAX_BITPOOL_SIZE * DIVIDE_VAL);
112 g_addressChecker[val / DIVIDE_VAL].slot |= (0x1 << (val % DIVIDE_VAL));
113 }
114
IsAddrExist(void * addr)115 inline bool IsAddrExist(void* addr)
116 {
117 if (!g_addressChecker) {
118 return true;
119 }
120 uint32_t val = AddrHash(static_cast<uint32_t>(reinterpret_cast<uint64_t>(addr))) % (MAX_BITPOOL_SIZE * DIVIDE_VAL);
121 if (g_addressChecker[val / DIVIDE_VAL].slot.load() & (0x1 << (val % DIVIDE_VAL))) {
122 return true;
123 }
124 return false;
125 }
126
GetDispatch()127 const MallocDispatchType* GetDispatch()
128 {
129 return g_dispatch.load(std::memory_order_relaxed);
130 }
131
InititalizeIPC()132 bool InititalizeIPC()
133 {
134 return true;
135 }
FinalizeIPC()136 void FinalizeIPC() {}
137
ConvertPid(char * buf)138 int ConvertPid(char* buf)
139 {
140 int count = 0;
141 char pidBuf[11] = {0}; /* 11: 32 bits to the maximum length of a string */
142 char *str = buf;
143 while (*str != '\0') {
144 if ((*str >= '0') && (*str <= '9') && (static_cast<unsigned long>(count) < sizeof(pidBuf) - 1)) {
145 pidBuf[count] = *str;
146 count++;
147 str++;
148 continue;
149 }
150
151 if (count > 0) {
152 break;
153 }
154 str++;
155 }
156 return atoi(pidBuf);
157 }
158
GetRealPid(void)159 pid_t GetRealPid(void)
160 {
161 const char *path = "/proc/self/status";
162 char buf[STATUS_LINE_SIZE] = {0};
163 FILE *fp = fopen(path, "r");
164 CHECK_NOTNULL(fp, -1, "fopen fail");
165 while (!feof(fp)) {
166 if (fgets(buf, STATUS_LINE_SIZE, fp) == nullptr) {
167 fclose(fp);
168 return -1;
169 }
170 if (strncmp(buf, "Pid:", PID_STR_SIZE) == 0) {
171 break;
172 }
173 }
174 (void)fclose(fp);
175 return static_cast<pid_t>(ConvertPid(buf));
176 }
177 } // namespace
178
GetCurThreadId()179 pid_t inline __attribute__((always_inline)) GetCurThreadId()
180 {
181 if (pthread_getspecific(g_hookTid) == nullptr) {
182 pthread_setspecific(g_hookTid, reinterpret_cast<void *>(GetThreadId()));
183 }
184 return reinterpret_cast<long>((pthread_getspecific(g_hookTid)));
185 }
186
UpdateThreadName(std::shared_ptr<HookSocketClient> & client)187 bool inline __attribute__((always_inline)) UpdateThreadName(std::shared_ptr<HookSocketClient>& client)
188 {
189 long updateCount = reinterpret_cast<long>(pthread_getspecific(g_updateThreadNameCount));
190 bool ret = true;
191 if (updateCount == 0) {
192 StackRawData tnameData = {{{{0}}}};
193 tnameData.tid = static_cast<uint32_t>(GetCurThreadId());
194 tnameData.type = THREAD_NAME_MSG;
195 prctl(PR_GET_NAME, tnameData.name);
196 ret = client->SendStackWithPayload(&tnameData,
197 sizeof(BaseStackRawData) + strlen(tnameData.name) + 1, nullptr, 0);
198 if (!ret) {
199 return ret;
200 }
201 }
202 pthread_setspecific(g_updateThreadNameCount,
203 reinterpret_cast<void *>(updateCount == UPDATE_THEARD_NAME ? 0 : updateCount + 1));
204 return ret;
205 }
206
GetTagId(std::shared_ptr<HookSocketClient> & client,const char * tagName)207 uint32_t inline __attribute__((always_inline)) GetTagId(std::shared_ptr<HookSocketClient>& client, const char* tagName)
208 {
209 if (tagName == nullptr || strlen(tagName) > PATH_MAX) {
210 return 0;
211 }
212 uint32_t tagId = 0;
213 bool isNewTag = false;
214 std::unique_lock<std::mutex> lock(g_tagMapMutex);
215 auto it = g_memTagMap.find(tagName);
216 if (it == g_memTagMap.end()) {
217 isNewTag = true;
218 tagId = g_memTagMap.size() + 1;
219 g_memTagMap[tagName] = tagId;
220 } else {
221 tagId = it->second;
222 }
223 lock.unlock();
224 if (isNewTag) {
225 StackRawData tagData = {{{{0}}}};
226 tagData.type = MEMORY_TAG;
227 tagData.tagId = tagId;
228 strcpy_s(tagData.name, PATH_MAX + 1, tagName);
229 if (client != nullptr) {
230 client->SendStackWithPayload(&tagData, sizeof(BaseStackRawData) + strlen(tagName) + 1, nullptr, 0);
231 }
232 }
233 return tagId;
234 }
235
236 static bool IsPidChanged(void);
237
MallocHookStart(void * disableHookCallback)238 void* MallocHookStart(void* disableHookCallback)
239 {
240 std::lock_guard<std::recursive_timed_mutex> guard(g_ClientMutex);
241 g_addressChecker = new Bitpool [MAX_BITPOOL_SIZE] {{0}};
242 g_mallocTimes = 0;
243 g_hookClient.reset();
244 if (g_hookClient != nullptr) {
245 return nullptr;
246 } else {
247 g_ClientConfig.Reset();
248 g_sampler.Reset();
249 g_hookClient = std::make_shared<HookSocketClient>(g_hookPid, &g_ClientConfig, &g_sampler,
250 reinterpret_cast<void (*)()>(disableHookCallback));
251 }
252 return nullptr;
253 }
254
ohos_malloc_hook_on_start(void (* disableHookCallback)())255 bool ohos_malloc_hook_on_start(void (*disableHookCallback)())
256 {
257 pthread_t threadStart;
258 if (pthread_create(&threadStart, nullptr, MallocHookStart,
259 reinterpret_cast<void *>(disableHookCallback))) {
260 return false;
261 }
262 pthread_detach(threadStart);
263 g_hookPid = GetRealPid();
264 pthread_key_create(&g_disableHookFlag, nullptr);
265 pthread_setspecific(g_disableHookFlag, nullptr);
266 pthread_key_create(&g_hookTid, nullptr);
267 pthread_setspecific(g_hookTid, nullptr);
268 pthread_key_create(&g_updateThreadNameCount, nullptr);
269 pthread_setspecific(g_updateThreadNameCount, reinterpret_cast<void *>(0));
270 GetMainThreadRuntimeStackRange(g_filterStaLibRange);
271 constexpr int paramBufferLen = 128;
272 char paramOutBuf[paramBufferLen] = {0};
273 int ret = GetParameter("persist.hiviewdfx.profiler.mem.filter", "", paramOutBuf, paramBufferLen);
274 if (ret > 0) {
275 int min = 0;
276 int max = 0;
277 if (sscanf_s(paramOutBuf, "%d,%d", &min, &max) == 2) { // 2: two parameters.
278 g_maxSize = max > 0 ? max : INT_MAX;
279 g_ClientConfig.filterSize = min > 0 ? min : 0;
280 }
281 }
282 return true;
283 }
284
ohos_release_on_end(void *)285 void* ohos_release_on_end(void*)
286 {
287 std::lock_guard<std::recursive_timed_mutex> guard(g_ClientMutex);
288 delete [] g_addressChecker;
289 g_addressChecker = nullptr;
290 g_hookClient = nullptr;
291 pthread_key_delete(g_disableHookFlag);
292 pthread_key_delete(g_hookTid);
293 pthread_key_delete(g_updateThreadNameCount);
294 g_ClientConfig.Reset();
295 return nullptr;
296 }
297
ohos_malloc_hook_on_end(void)298 bool ohos_malloc_hook_on_end(void)
299 {
300 {
301 std::lock_guard<std::recursive_timed_mutex> guard(g_ClientMutex);
302 if (g_hookClient != nullptr) {
303 if (g_hookClient->GetNmdType() == 1) {
304 g_hookClient->SendNmdInfo();
305 }
306 g_hookClient->SendEndMsg();
307 g_hookClient->Flush();
308 }
309 }
310 pthread_t threadEnd;
311 if (pthread_create(&threadEnd, nullptr, ohos_release_on_end, nullptr)) {
312 return false;
313 }
314 pthread_detach(threadEnd);
315 return true;
316 }
317
FilterStandardSoIp(uint64_t ip)318 bool FilterStandardSoIp(uint64_t ip)
319 {
320 for (auto [soBegin, soEnd_]: g_filterStaLibRange) {
321 if (ip >= soBegin && ip < soEnd_) {
322 return true;
323 }
324 }
325 return false;
326 }
327
328 #if defined(__aarch64__)
FpUnwind(int maxDepth,uint64_t * ip,int stackSize,const char * startPtr,const char * endPtr)329 static int inline __attribute__((always_inline)) FpUnwind(int maxDepth, uint64_t* ip, int stackSize,
330 const char* startPtr, const char* endPtr)
331 {
332 void** startfp = (void**)__builtin_frame_address(0);
333 void** fp = startfp;
334 int depth = 0;
335 int count = 0;
336 uint64_t tempIp = 0;
337 while (depth < maxDepth) {
338 if (fp < (void**)startPtr || (fp + 1) >= (void**)endPtr) {
339 break;
340 }
341 void** nextFp = (void**)*fp;
342 if (nextFp <= fp) {
343 break;
344 }
345 if (((nextFp - startfp) * sizeof(void*)) > static_cast<unsigned long>(stackSize)) {
346 break;
347 }
348 fp = nextFp;
349 tempIp = *(reinterpret_cast<unsigned long*>(fp + 1));
350 if (tempIp <= TEMP_IP) {
351 break;
352 }
353 if (g_ClientConfig.responseLibraryMode) {
354 if (++count >= RESPONSE_LIBRARY_MODE_DEPTH || !FilterStandardSoIp(tempIp)) {
355 break;
356 }
357 } else {
358 ip[depth++] = tempIp;
359 }
360 }
361 if (g_ClientConfig.responseLibraryMode) {
362 ip[0] = tempIp;
363 depth = 1;
364 }
365 return depth;
366 }
367
getJsChainId()368 uint64_t getJsChainId()
369 {
370 if (g_ClientConfig.arktsConfig.jsStackReport > 0) {
371 OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
372 if (hitraceId.IsValid()) {
373 return hitraceId.GetChainId();
374 }
375 }
376 return 0;
377 }
378 #endif
379
hook_malloc(void * (* fn)(size_t),size_t size)380 void* hook_malloc(void* (*fn)(size_t), size_t size)
381 {
382 void* ret = nullptr;
383 if (fn) {
384 ret = fn(size);
385 }
386 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
387 return ret;
388 }
389 if (!ohos_set_filter_size(size, ret)) {
390 return ret;
391 }
392
393 #ifdef PERFORMANCE_DEBUG
394 struct timespec start = {};
395 clock_gettime(CLOCK_REALTIME, &start);
396 #endif
397
398 if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size) == 0) { //0 not sampling
399 #ifdef PERFORMANCE_DEBUG
400 g_mallocTimes++;
401 struct timespec end = {};
402 clock_gettime(CLOCK_REALTIME, &end);
403 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
404 if (g_mallocTimes % PRINT_INTERVAL == 0) {
405 PROFILER_LOG_ERROR(LOG_CORE,
406 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
407 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
408 }
409 #endif
410 return ret;
411 }
412
413 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
414 auto holder = weakClient.lock();
415 if (holder == nullptr) {
416 return ret;
417 }
418 if (!UpdateThreadName(holder)) {
419 return ret;
420 }
421 StackRawData rawdata = {{{{0}}}};
422 const char* stackptr = nullptr;
423 const char* stackendptr = nullptr;
424 int stackSize = 0;
425 int fpStackDepth = 0;
426 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
427
428 if (g_ClientConfig.fpunwind) {
429 #ifdef __aarch64__
430 void* stackAddr = nullptr;
431 size_t coroutineStackSize = 0;
432 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
433 stackSize = static_cast<int>(coroutineStackSize);
434 stackptr = reinterpret_cast<const char*>(stackAddr);
435 stackendptr = stackptr + coroutineStackSize;
436 } else {
437 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
438 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
439 stackSize = stackendptr - stackptr;
440 }
441 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
442 stackSize = 0;
443 rawdata.jsChainId = getJsChainId();
444 #endif
445 } else {
446 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
447 GetLocalRegs(regs);
448 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
449 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
450 stackSize = stackendptr - stackptr;
451 if (stackendptr == nullptr) {
452 stackSize = 0;
453 }
454 }
455 rawdata.type = MALLOC_MSG;
456 rawdata.pid = static_cast<uint32_t>(g_hookPid);
457 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
458 rawdata.mallocSize = size;
459 rawdata.addr = ret;
460 if (g_ClientConfig.sampleInterval >= THRESHOLD) {
461 Addr2Bitpool(ret);
462 }
463 int realSize = 0;
464 if (g_ClientConfig.fpunwind) {
465 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
466 } else {
467 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
468 }
469 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
470 g_mallocTimes++;
471 #ifdef PERFORMANCE_DEBUG
472 struct timespec end = {};
473 clock_gettime(CLOCK_REALTIME, &end);
474 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
475 g_dataCounts += stackSize;
476 if (g_mallocTimes % PRINT_INTERVAL == 0) {
477 PROFILER_LOG_ERROR(LOG_CORE,
478 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
479 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
480 }
481 #endif
482 return ret;
483 }
484
hook_aligned_alloc(void * (* fn)(size_t,size_t),size_t align,size_t len)485 void* hook_aligned_alloc(void* (*fn)(size_t, size_t), size_t align, size_t len)
486 {
487 void* ret = nullptr;
488 if (fn) {
489 ret = fn(align, len);
490 }
491 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
492 return ret;
493 }
494 if (!ohos_set_filter_size(len, ret)) {
495 return ret;
496 }
497
498 #ifdef PERFORMANCE_DEBUG
499 struct timespec start = {};
500 clock_gettime(CLOCK_REALTIME, &start);
501 #endif
502
503 if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(len) == 0) { //0 not sampling
504 #ifdef PERFORMANCE_DEBUG
505 g_mallocTimes++;
506 struct timespec end = {};
507 clock_gettime(CLOCK_REALTIME, &end);
508 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
509 if (g_mallocTimes % PRINT_INTERVAL == 0) {
510 PROFILER_LOG_ERROR(LOG_CORE,
511 "g_aligned_allocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %"
512 PRIu64"\n", g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(),
513 g_timeCost.load() / g_mallocTimes.load());
514 }
515 #endif
516 return ret;
517 }
518
519 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
520 auto holder = weakClient.lock();
521 if (holder == nullptr) {
522 return ret;
523 }
524 if (!UpdateThreadName(holder)) {
525 return ret;
526 }
527 StackRawData rawdata = {{{{0}}}};
528 const char* stackptr = nullptr;
529 const char* stackendptr = nullptr;
530 int stackSize = 0;
531 int fpStackDepth = 0;
532 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
533
534 if (g_ClientConfig.fpunwind) {
535 #ifdef __aarch64__
536 void* stackAddr = nullptr;
537 size_t coroutineStackSize = 0;
538 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
539 stackSize = static_cast<int>(coroutineStackSize);
540 stackptr = reinterpret_cast<const char*>(stackAddr);
541 stackendptr = stackptr + coroutineStackSize;
542 } else {
543 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
544 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
545 stackSize = stackendptr - stackptr;
546 }
547 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
548 stackSize = 0;
549 rawdata.jsChainId = getJsChainId();
550 #endif
551 } else {
552 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
553 GetLocalRegs(regs);
554 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
555 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
556 stackSize = stackendptr - stackptr;
557 if (stackendptr == nullptr) {
558 stackSize = 0;
559 }
560 }
561 rawdata.type = MALLOC_MSG;
562 rawdata.pid = static_cast<uint32_t>(g_hookPid);
563 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
564 rawdata.mallocSize = len;
565 rawdata.addr = ret;
566 if (g_ClientConfig.sampleInterval >= THRESHOLD) {
567 Addr2Bitpool(ret);
568 }
569 int realSize = 0;
570 if (g_ClientConfig.fpunwind) {
571 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
572 } else {
573 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
574 }
575 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
576 g_mallocTimes++;
577 #ifdef PERFORMANCE_DEBUG
578 struct timespec end = {};
579 clock_gettime(CLOCK_REALTIME, &end);
580 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
581 g_dataCounts += stackSize;
582 if (g_mallocTimes % PRINT_INTERVAL == 0) {
583 PROFILER_LOG_ERROR(LOG_CORE,
584 "g_aligned_allocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %"
585 PRIu64"\n", g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(),
586 g_timeCost.load() / g_mallocTimes.load());
587 }
588 #endif
589 return ret;
590 }
591
hook_valloc(void * (* fn)(size_t),size_t size)592 void* hook_valloc(void* (*fn)(size_t), size_t size)
593 {
594 void* pRet = nullptr;
595 if (fn) {
596 pRet = fn(size);
597 }
598 return pRet;
599 }
600
hook_calloc(void * (* fn)(size_t,size_t),size_t number,size_t size)601 void* hook_calloc(void* (*fn)(size_t, size_t), size_t number, size_t size)
602 {
603 void* pRet = nullptr;
604 if (fn) {
605 pRet = fn(number, size);
606 }
607 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
608 return pRet;
609 }
610 if (!ohos_set_filter_size(number * size, pRet)) {
611 return pRet;
612 }
613
614 #ifdef PERFORMANCE_DEBUG
615 struct timespec start = {};
616 clock_gettime(CLOCK_REALTIME, &start);
617 #endif
618
619 if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size * number) == 0) {
620 #ifdef PERFORMANCE_DEBUG
621 g_mallocTimes++;
622 struct timespec end = {};
623 clock_gettime(CLOCK_REALTIME, &end);
624 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
625 if (g_mallocTimes % PRINT_INTERVAL == 0) {
626 PROFILER_LOG_ERROR(LOG_CORE,
627 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
628 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
629 }
630 #endif
631 return pRet;
632 }
633 StackRawData rawdata = {{{{0}}}};
634 const char* stackptr = nullptr;
635 const char* stackendptr = nullptr;
636 int stackSize = 0;
637 int fpStackDepth = 0;
638 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
639
640 if (g_ClientConfig.fpunwind) {
641 #ifdef __aarch64__
642 void* stackAddr = nullptr;
643 size_t coroutineStackSize = 0;
644 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
645 stackSize = static_cast<int>(coroutineStackSize);
646 stackptr = reinterpret_cast<const char*>(stackAddr);
647 stackendptr = stackptr + coroutineStackSize;
648 } else {
649 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
650 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
651 stackSize = stackendptr - stackptr;
652 }
653 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
654 stackSize = 0;
655 rawdata.jsChainId = getJsChainId();
656 #endif
657 } else {
658 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
659 GetLocalRegs(regs);
660 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
661 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
662 stackSize = stackendptr - stackptr;
663 if (stackendptr == nullptr) {
664 stackSize = 0;
665 }
666 }
667
668 rawdata.type = MALLOC_MSG;
669 rawdata.pid = static_cast<uint32_t>(g_hookPid);
670 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
671 rawdata.mallocSize = number * size;
672 rawdata.addr = pRet;
673 if (g_ClientConfig.sampleInterval >= THRESHOLD) {
674 Addr2Bitpool(pRet);
675 }
676 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
677 auto holder = weakClient.lock();
678 if (holder != nullptr) {
679 int realSize = 0;
680 if (g_ClientConfig.fpunwind) {
681 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
682 } else {
683 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
684 }
685 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
686 }
687 g_mallocTimes++;
688 #ifdef PERFORMANCE_DEBUG
689 struct timespec end = {};
690 clock_gettime(CLOCK_REALTIME, &end);
691 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
692 if (g_mallocTimes % PRINT_INTERVAL == 0) {
693 PROFILER_LOG_ERROR(LOG_CORE,
694 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
695 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
696 }
697 #endif
698 return pRet;
699 }
700
hook_memalign(void * (* fn)(size_t,size_t),size_t align,size_t bytes)701 void* hook_memalign(void* (*fn)(size_t, size_t), size_t align, size_t bytes)
702 {
703 void* pRet = nullptr;
704 if (fn) {
705 pRet = fn(align, bytes);
706 }
707 return pRet;
708 }
709
hook_realloc(void * (* fn)(void *,size_t),void * ptr,size_t size)710 void* hook_realloc(void* (*fn)(void*, size_t), void* ptr, size_t size)
711 {
712 void* pRet = nullptr;
713 if (fn) {
714 pRet = fn(ptr, size);
715 }
716 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
717 return pRet;
718 }
719 if (!ohos_set_filter_size(size, pRet)) {
720 return pRet;
721 }
722
723 #ifdef PERFORMANCE_DEBUG
724 struct timespec start = {};
725 clock_gettime(CLOCK_REALTIME, &start);
726 #endif
727
728 if (g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL && g_sampler.StartSampling(size) == 0) {
729 #ifdef PERFORMANCE_DEBUG
730 g_mallocTimes++;
731 struct timespec end = {};
732 clock_gettime(CLOCK_REALTIME, &end);
733 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
734 if (g_mallocTimes % PRINT_INTERVAL == 0) {
735 PROFILER_LOG_ERROR(LOG_CORE,
736 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
737 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
738 }
739 #endif
740 return pRet;
741 }
742 StackRawData rawdata = {{{{0}}}};
743 StackRawData freeData = {{{{0}}}};
744 const char* stackptr = nullptr;
745 const char* stackendptr = nullptr;
746 int stackSize = 0;
747 int fpStackDepth = 0;
748 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
749
750 if (g_ClientConfig.fpunwind) {
751 #ifdef __aarch64__
752 void* stackAddr = nullptr;
753 size_t coroutineStackSize = 0;
754 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
755 stackSize = static_cast<int>(coroutineStackSize);
756 stackptr = reinterpret_cast<const char*>(stackAddr);
757 stackendptr = stackptr + coroutineStackSize;
758 } else {
759 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
760 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
761 stackSize = stackendptr - stackptr;
762 }
763 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
764 stackSize = 0;
765 if (g_ClientConfig.freeStackData) {
766 (void)memcpy_s(freeData.ip, sizeof(freeData.ip) / sizeof(uint64_t),
767 rawdata.ip, sizeof(rawdata.ip) / sizeof(uint64_t));
768 }
769 #endif
770 } else {
771 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
772 GetLocalRegs(regs);
773 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
774 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
775 stackSize = stackendptr - stackptr;
776 if (stackendptr == nullptr) {
777 stackSize = 0;
778 }
779 if (g_ClientConfig.freeStackData) {
780 (void)memcpy_s(freeData.regs, sizeof(freeData.regs) / sizeof(char),
781 rawdata.regs, sizeof(rawdata.regs) / sizeof(char));
782 }
783 }
784
785 rawdata.type = MALLOC_MSG;
786 rawdata.pid = static_cast<uint32_t>(g_hookPid);
787 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
788 rawdata.mallocSize = size;
789 rawdata.addr = pRet;
790 if (g_ClientConfig.sampleInterval >= THRESHOLD) {
791 Addr2Bitpool(pRet);
792 }
793 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
794 auto holder = weakClient.lock();
795 if (holder != nullptr) {
796 int realSize = 0;
797 int freeRealSize = 0;
798 freeData.type = FREE_MSG;
799 freeData.pid = rawdata.pid;
800 freeData.tid = rawdata.tid;
801 freeData.mallocSize = 0;
802 freeData.addr = ptr;
803 freeData.ts = rawdata.ts;
804 if (g_ClientConfig.fpunwind) {
805 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
806 freeRealSize = sizeof(BaseStackRawData);
807 } else {
808 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
809 freeRealSize = realSize;
810 }
811 holder->SendStackWithPayload(&freeData, freeRealSize, nullptr, 0); // 0: Don't unwind the freeData
812 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
813 }
814 #ifdef PERFORMANCE_DEBUG
815 g_mallocTimes++;
816 struct timespec end = {};
817 clock_gettime(CLOCK_REALTIME, &end);
818 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
819 if (g_mallocTimes % PRINT_INTERVAL == 0) {
820 PROFILER_LOG_ERROR(LOG_CORE,
821 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
822 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
823 }
824 #endif
825 return pRet;
826 }
827
hook_malloc_usable_size(size_t (* fn)(void *),void * ptr)828 size_t hook_malloc_usable_size(size_t (*fn)(void*), void* ptr)
829 {
830 size_t ret = 0;
831 if (fn) {
832 ret = fn(ptr);
833 }
834
835 return ret;
836 }
837
hook_free(void (* free_func)(void *),void * p)838 void hook_free(void (*free_func)(void*), void* p)
839 {
840 if (g_ClientConfig.statisticsInterval > 0) {
841 if (!free_func) {
842 return;
843 }
844 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
845 free_func(p);
846 return;
847 }
848 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
849 auto holder = weakClient.lock();
850 if ((holder != nullptr) && p) {
851 holder->SendStackWithPayload(&p, sizeof(void*), nullptr, 0);
852 }
853 free_func(p);
854 #ifdef PERFORMANCE_DEBUG
855 g_mallocTimes++;
856 struct timespec end = {};
857 clock_gettime(CLOCK_REALTIME, &end);
858 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
859 if (g_mallocTimes % PRINT_INTERVAL == 0) {
860 PROFILER_LOG_ERROR(LOG_CORE,
861 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
862 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
863 }
864 #endif
865 return;
866 }
867 struct timespec freeTime = {};
868 clock_gettime(g_ClientConfig.clockId, &freeTime);
869 if (free_func) {
870 free_func(p);
871 }
872 if (g_ClientConfig.mallocDisable || IsPidChanged()) {
873 return;
874 }
875 if (g_ClientConfig.sampleInterval >= THRESHOLD) {
876 if (!IsAddrExist(p)) {
877 return;
878 }
879 }
880 #ifdef PERFORMANCE_DEBUG
881 struct timespec start = {};
882 clock_gettime(CLOCK_REALTIME, &start);
883 #endif
884
885 StackRawData rawdata = {{{{0}}}};
886 const char* stackptr = nullptr;
887 const char* stackendptr = nullptr;
888 int stackSize = 0;
889 int fpStackDepth = 0;
890 rawdata.ts = freeTime;
891
892 if (g_ClientConfig.freeStackData) {
893 if (g_ClientConfig.fpunwind) {
894 #ifdef __aarch64__
895 void* stackAddr = nullptr;
896 size_t coroutineStackSize = 0;
897 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
898 stackSize = static_cast<int>(coroutineStackSize);
899 stackptr = reinterpret_cast<const char*>(stackAddr);
900 stackendptr = stackptr + coroutineStackSize;
901 } else {
902 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
903 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
904 stackSize = stackendptr - stackptr;
905 }
906 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
907 stackSize = 0;
908 rawdata.jsChainId = getJsChainId();
909 #endif
910 } else {
911 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
912 GetLocalRegs(regs);
913 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
914 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
915 stackSize = stackendptr - stackptr;
916 if (stackendptr == nullptr) {
917 stackSize = 0;
918 }
919 }
920 }
921
922 rawdata.type = FREE_MSG;
923 rawdata.pid = static_cast<uint32_t>(g_hookPid);
924 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
925 rawdata.mallocSize = 0;
926 rawdata.addr = p;
927 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
928 auto holder = weakClient.lock();
929 if (holder != nullptr) {
930 int realSize = 0;
931 if (g_ClientConfig.fpunwind) {
932 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
933 } else {
934 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
935 }
936 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
937 }
938 #ifdef PERFORMANCE_DEBUG
939 g_mallocTimes++;
940 struct timespec end = {};
941 clock_gettime(CLOCK_REALTIME, &end);
942 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
943 if (g_mallocTimes % PRINT_INTERVAL == 0) {
944 PROFILER_LOG_ERROR(LOG_CORE,
945 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
946 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
947 }
948 #endif
949 }
950
SendMmapFileRawData(int prot,int flags,off_t offset,const std::string & filePath,const StackRawData & rawdata,std::shared_ptr<HookSocketClient> & holder)951 inline void SendMmapFileRawData(int prot, int flags, off_t offset, const std::string& filePath,
952 const StackRawData& rawdata, std::shared_ptr<HookSocketClient>& holder)
953 {
954 StackRawData curRawdata = {{{{0}}}};
955 curRawdata.addr = rawdata.addr;
956 curRawdata.pid = static_cast<uint32_t>(g_hookPid);
957 curRawdata.mallocSize = rawdata.mallocSize;
958 curRawdata.mmapArgs.offset = offset;
959 curRawdata.type = OHOS::Developtools::NativeDaemon::MMAP_FILE_TYPE;
960 if (prot & PROT_EXEC) {
961 curRawdata.mmapArgs.flags |= PROT_EXEC;
962 }
963 size_t len = strlen(filePath.c_str()) + 1;
964 if (strncpy_s(curRawdata.name, PATH_MAX + 1, filePath.c_str(), len) != EOK) {
965 return;
966 }
967 if (flags & MAP_FIXED) {
968 curRawdata.mmapArgs.flags |= MAP_FIXED;
969 }
970 holder->SendStackWithPayload(&curRawdata, sizeof(BaseStackRawData) + len, nullptr, 0);
971 }
972
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)973 void* hook_mmap(void*(*fn)(void*, size_t, int, int, int, off_t),
974 void* addr, size_t length, int prot, int flags, int fd, off_t offset)
975 {
976 void* ret = nullptr;
977 if (fn) {
978 ret = fn(addr, length, prot, flags, fd, offset);
979 }
980 if (g_ClientConfig.mmapDisable || IsPidChanged()) {
981 return ret;
982 }
983
984 #ifdef PERFORMANCE_DEBUG
985 struct timespec start = {};
986 clock_gettime(CLOCK_REALTIME, &start);
987 #endif
988
989 if ((fd < 0 && offset == 0) && g_ClientConfig.sampleInterval > MIN_SAMPLER_INTERVAL
990 && g_sampler.StartSampling(length) == 0) {
991 #ifdef PERFORMANCE_DEBUG
992 g_mallocTimes++;
993 struct timespec end = {};
994 clock_gettime(CLOCK_REALTIME, &end);
995 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
996 if (g_mallocTimes % PRINT_INTERVAL == 0) {
997 PROFILER_LOG_ERROR(LOG_CORE,
998 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
999 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
1000 }
1001 #endif
1002 return ret;
1003 }
1004 StackRawData rawdata = {{{{0}}}};
1005 const char* stackptr = nullptr;
1006 const char* stackendptr = nullptr;
1007 int stackSize = 0;
1008 int fpStackDepth = 0;
1009 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
1010
1011 if (g_ClientConfig.fpunwind) {
1012 #ifdef __aarch64__
1013 void* stackAddr = nullptr;
1014 size_t coroutineStackSize = 0;
1015 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
1016 stackSize = static_cast<int>(coroutineStackSize);
1017 stackptr = reinterpret_cast<const char*>(stackAddr);
1018 stackendptr = stackptr + coroutineStackSize;
1019 } else {
1020 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
1021 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1022 stackSize = stackendptr - stackptr;
1023 }
1024 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
1025 stackSize = 0;
1026 rawdata.jsChainId = getJsChainId();
1027 #endif
1028 } else {
1029 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
1030 GetLocalRegs(regs);
1031 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
1032 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1033 stackSize = stackendptr - stackptr;
1034 if (stackendptr == nullptr) {
1035 stackSize = 0;
1036 }
1037 }
1038
1039 rawdata.type = MMAP_MSG;
1040 rawdata.pid = static_cast<uint32_t>(g_hookPid);
1041 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
1042 rawdata.mallocSize = length;
1043 rawdata.addr = ret;
1044 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
1045 auto holder = weakClient.lock();
1046 if (holder == nullptr) {
1047 return ret;
1048 }
1049 if (fd >= 0) {
1050 rawdata.type = MMAP_FILE_PAGE_MSG;
1051 char path[FD_PATH_LENGTH] = {0};
1052 char fileName[PATH_MAX + 1] = {0};
1053 (void)snprintf_s(path, FD_PATH_LENGTH, FD_PATH_LENGTH - 1, "/proc/self/fd/%d", fd);
1054 ssize_t len = readlink(path, fileName, sizeof(fileName) - 1);
1055 if (len != -1) {
1056 fileName[len] = '\0';
1057 SendMmapFileRawData(prot, flags, offset, fileName, rawdata, holder);
1058 char* p = strrchr(fileName, '/');
1059 if (p != nullptr) {
1060 rawdata.tagId = GetTagId(holder, &fileName[p - fileName + 1]);
1061 } else {
1062 rawdata.tagId = GetTagId(holder, fileName);
1063 }
1064 }
1065 }
1066 if (!UpdateThreadName(holder)) {
1067 return ret;
1068 }
1069 int realSize = 0;
1070 if (g_ClientConfig.fpunwind) {
1071 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
1072 } else {
1073 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
1074 }
1075 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
1076 #ifdef PERFORMANCE_DEBUG
1077 g_mallocTimes++;
1078 struct timespec end = {};
1079 clock_gettime(CLOCK_REALTIME, &end);
1080 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
1081 if (g_mallocTimes % PRINT_INTERVAL == 0) {
1082 PROFILER_LOG_ERROR(LOG_CORE,
1083 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
1084 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
1085 }
1086 #endif
1087 return ret;
1088 }
1089
hook_munmap(int (* fn)(void *,size_t),void * addr,size_t length)1090 int hook_munmap(int(*fn)(void*, size_t), void* addr, size_t length)
1091 {
1092 int ret = -1;
1093 struct timespec unmapTime = {};
1094 clock_gettime(g_ClientConfig.clockId, &unmapTime);
1095 if (fn) {
1096 ret = fn(addr, length);
1097 }
1098 if (g_ClientConfig.mmapDisable || IsPidChanged()) {
1099 return ret;
1100 }
1101
1102 #ifdef PERFORMANCE_DEBUG
1103 struct timespec start = {};
1104 clock_gettime(CLOCK_REALTIME, &start);
1105 #endif
1106
1107 int stackSize = 0;
1108 StackRawData rawdata = {{{{0}}}};
1109 const char* stackptr = nullptr;
1110 const char* stackendptr = nullptr;
1111 int fpStackDepth = 0;
1112 rawdata.ts = unmapTime;
1113 if (g_ClientConfig.munmapStackData) {
1114 if (g_ClientConfig.fpunwind) {
1115 #ifdef __aarch64__
1116 void* stackAddr = nullptr;
1117 size_t coroutineStackSize = 0;
1118 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
1119 stackSize = static_cast<int>(coroutineStackSize);
1120 stackptr = reinterpret_cast<const char*>(stackAddr);
1121 stackendptr = stackptr + coroutineStackSize;
1122 } else {
1123 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
1124 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1125 stackSize = stackendptr - stackptr;
1126 }
1127 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
1128 stackSize = 0;
1129 rawdata.jsChainId = getJsChainId();
1130 #endif
1131 } else {
1132 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
1133 GetLocalRegs(regs);
1134 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
1135 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1136 stackSize = stackendptr - stackptr;
1137 if (stackendptr == nullptr) {
1138 stackSize = 0;
1139 }
1140 }
1141 }
1142
1143 rawdata.type = MUNMAP_MSG;
1144 rawdata.pid = static_cast<uint32_t>(g_hookPid);
1145 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
1146 rawdata.mallocSize = length;
1147 rawdata.addr = addr;
1148 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
1149 auto holder = weakClient.lock();
1150 if (holder != nullptr) {
1151 int realSize = 0;
1152 if (g_ClientConfig.fpunwind) {
1153 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
1154 } else {
1155 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
1156 }
1157 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
1158 }
1159 #ifdef PERFORMANCE_DEBUG
1160 g_mallocTimes++;
1161 struct timespec end = {};
1162 clock_gettime(CLOCK_REALTIME, &end);
1163 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
1164 if (g_mallocTimes % PRINT_INTERVAL == 0) {
1165 PROFILER_LOG_ERROR(LOG_CORE,
1166 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
1167 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
1168 }
1169 #endif
1170 return ret;
1171 }
1172
hook_prctl(int (* fn)(int,...),int option,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)1173 int hook_prctl(int(*fn)(int, ...),
1174 int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
1175 {
1176 int ret = -1;
1177 if (fn) {
1178 ret = fn(option, arg2, arg3, arg4, arg5);
1179 }
1180 if (reinterpret_cast<char*>(arg5) == nullptr || IsPidChanged()) {
1181 return ret;
1182 }
1183 if (option == PR_SET_VMA && arg2 == PR_SET_VMA_ANON_NAME) {
1184 #ifdef PERFORMANCE_DEBUG
1185 struct timespec start = {};
1186 clock_gettime(CLOCK_REALTIME, &start);
1187 #endif
1188 StackRawData rawdata = {{{{0}}}};
1189 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
1190 rawdata.type = PR_SET_VMA_MSG;
1191 rawdata.pid = static_cast<uint32_t>(g_hookPid);
1192 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
1193 rawdata.mallocSize = arg4;
1194 rawdata.addr = reinterpret_cast<void*>(arg3);
1195 size_t tagLen = strlen(reinterpret_cast<char*>(arg5)) + 1;
1196 if (memcpy_s(rawdata.name, sizeof(rawdata.name), reinterpret_cast<char*>(arg5), tagLen) != EOK) {
1197 HILOG_ERROR(LOG_CORE, "memcpy_s tag failed");
1198 }
1199 rawdata.name[sizeof(rawdata.name) - 1] = '\0';
1200 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
1201 auto holder = weakClient.lock();
1202 if (holder != nullptr) {
1203 holder->SendStackWithPayload(&rawdata, sizeof(BaseStackRawData) + tagLen, nullptr, 0);
1204 }
1205 #ifdef PERFORMANCE_DEBUG
1206 g_mallocTimes++;
1207 struct timespec end = {};
1208 clock_gettime(CLOCK_REALTIME, &end);
1209 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
1210 if (g_mallocTimes % PRINT_INTERVAL == 0) {
1211 PROFILER_LOG_ERROR(LOG_CORE,
1212 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
1213 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
1214 }
1215 #endif
1216 }
1217 return ret;
1218 }
1219
hook_memtrace(void * addr,size_t size,const char * tag,bool isUsing)1220 void hook_memtrace(void* addr, size_t size, const char* tag, bool isUsing)
1221 {
1222 if (!g_ClientConfig.memtraceEnable || IsPidChanged()) {
1223 return;
1224 }
1225 #ifdef PERFORMANCE_DEBUG
1226 struct timespec start = {};
1227 clock_gettime(CLOCK_REALTIME, &start);
1228 #endif
1229 int stackSize = 0;
1230 StackRawData rawdata = {{{{0}}}};
1231 const char* stackptr = nullptr;
1232 const char* stackendptr = nullptr;
1233 int fpStackDepth = 0;
1234 clock_gettime(g_ClientConfig.clockId, &rawdata.ts);
1235
1236 if (isUsing) {
1237 if (g_ClientConfig.fpunwind) {
1238 #ifdef __aarch64__
1239 void* stackAddr = nullptr;
1240 size_t coroutineStackSize = 0;
1241 if (ffrt_get_current_coroutine_stack(&stackAddr, &coroutineStackSize)) {
1242 stackSize = static_cast<int>(coroutineStackSize);
1243 stackptr = reinterpret_cast<const char*>(stackAddr);
1244 stackendptr = stackptr + coroutineStackSize;
1245 } else {
1246 stackptr = reinterpret_cast<const char*>(__builtin_frame_address(0));
1247 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1248 stackSize = stackendptr - stackptr;
1249 }
1250 fpStackDepth = FpUnwind(g_ClientConfig.maxStackDepth, rawdata.ip, stackSize, stackptr, stackendptr);
1251 stackSize = 0;
1252 rawdata.jsChainId = getJsChainId();
1253 #endif
1254 } else {
1255 unsigned long* regs = reinterpret_cast<unsigned long*>(&(rawdata.regs));
1256 GetLocalRegs(regs);
1257 stackptr = reinterpret_cast<const char*>(regs[RegisterGetSP(buildArchType)]);
1258 GetRuntimeStackEnd(stackptr, &stackendptr, g_hookPid, GetCurThreadId()); // stack end pointer
1259 stackSize = stackendptr - stackptr;
1260 if (stackendptr == nullptr) {
1261 stackSize = 0;
1262 }
1263 }
1264 }
1265 rawdata.type = isUsing ? MEMORY_USING_MSG : MEMORY_UNUSING_MSG;
1266 rawdata.pid = static_cast<uint32_t>(g_hookPid);
1267 rawdata.tid = static_cast<uint32_t>(GetCurThreadId());
1268 rawdata.mallocSize = size;
1269 rawdata.addr = addr;
1270 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
1271 auto holder = weakClient.lock();
1272 rawdata.tagId = isUsing ? GetTagId(holder, tag) : 0;
1273 if (holder != nullptr) {
1274 int realSize = 0;
1275 if (g_ClientConfig.fpunwind) {
1276 realSize = sizeof(BaseStackRawData) + (fpStackDepth * sizeof(uint64_t));
1277 } else {
1278 realSize = sizeof(BaseStackRawData) + sizeof(rawdata.regs);
1279 }
1280 holder->SendStackWithPayload(&rawdata, realSize, stackptr, stackSize);
1281 }
1282 #ifdef PERFORMANCE_DEBUG
1283 g_mallocTimes++;
1284 struct timespec end = {};
1285 clock_gettime(CLOCK_REALTIME, &end);
1286 g_timeCost += (end.tv_sec - start.tv_sec) * S_TO_NS + (end.tv_nsec - start.tv_nsec);
1287 if (g_mallocTimes % PRINT_INTERVAL == 0) {
1288 PROFILER_LOG_ERROR(LOG_CORE,
1289 "g_mallocTimes %" PRIu64" cost time = %" PRIu64" copy data bytes = %" PRIu64" mean cost = %" PRIu64"\n",
1290 g_mallocTimes.load(), g_timeCost.load(), g_dataCounts.load(), g_timeCost.load() / g_mallocTimes.load());
1291 }
1292 #endif
1293 }
1294
ohos_malloc_hook_initialize(const MallocDispatchType * malloc_dispatch,bool *,const char *)1295 bool ohos_malloc_hook_initialize(const MallocDispatchType*malloc_dispatch, bool*, const char*)
1296 {
1297 g_dispatch.store(malloc_dispatch);
1298 InititalizeIPC();
1299 return true;
1300 }
ohos_malloc_hook_finalize(void)1301 void ohos_malloc_hook_finalize(void)
1302 {
1303 FinalizeIPC();
1304 }
1305
ohos_malloc_hook_malloc(size_t size)1306 void* ohos_malloc_hook_malloc(size_t size)
1307 {
1308 __set_hook_flag(false);
1309 void* ret = hook_malloc(GetDispatch()->malloc, size);
1310 __set_hook_flag(true);
1311 return ret;
1312 }
1313
ohos_malloc_hook_realloc(void * ptr,size_t size)1314 void* ohos_malloc_hook_realloc(void* ptr, size_t size)
1315 {
1316 __set_hook_flag(false);
1317 void* ret = hook_realloc(GetDispatch()->realloc, ptr, size);
1318 __set_hook_flag(true);
1319 return ret;
1320 }
1321
ohos_malloc_hook_calloc(size_t number,size_t size)1322 void* ohos_malloc_hook_calloc(size_t number, size_t size)
1323 {
1324 __set_hook_flag(false);
1325 void* ret = hook_calloc(GetDispatch()->calloc, number, size);
1326 __set_hook_flag(true);
1327 return ret;
1328 }
1329
ohos_malloc_hook_valloc(size_t size)1330 void* ohos_malloc_hook_valloc(size_t size)
1331 {
1332 __set_hook_flag(false);
1333 void* ret = hook_valloc(GetDispatch()->valloc, size);
1334 __set_hook_flag(true);
1335 return ret;
1336 }
1337
ohos_malloc_hook_free(void * p)1338 void ohos_malloc_hook_free(void* p)
1339 {
1340 __set_hook_flag(false);
1341 hook_free(GetDispatch()->free, p);
1342 __set_hook_flag(true);
1343 }
1344
ohos_malloc_hook_malloc_usable_size(void * mem)1345 size_t ohos_malloc_hook_malloc_usable_size(void* mem)
1346 {
1347 __set_hook_flag(false);
1348 size_t ret = hook_malloc_usable_size(GetDispatch()->malloc_usable_size, mem);
1349 __set_hook_flag(true);
1350 return ret;
1351 }
1352
ohos_malloc_hook_get_hook_flag(void)1353 bool ohos_malloc_hook_get_hook_flag(void)
1354 {
1355 return pthread_getspecific(g_disableHookFlag) == nullptr;
1356 }
1357
ohos_malloc_hook_set_hook_flag(bool flag)1358 bool ohos_malloc_hook_set_hook_flag(bool flag)
1359 {
1360 bool oldFlag = ohos_malloc_hook_get_hook_flag();
1361 if (flag) {
1362 pthread_setspecific(g_disableHookFlag, nullptr);
1363 } else {
1364 pthread_setspecific(g_disableHookFlag, reinterpret_cast<void *>(1));
1365 }
1366 return oldFlag;
1367 }
1368
ohos_malloc_hook_mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)1369 void* ohos_malloc_hook_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
1370 {
1371 __set_hook_flag(false);
1372 void* ret = hook_mmap(GetDispatch()->mmap, addr, length, prot, flags, fd, offset);
1373 __set_hook_flag(true);
1374 return ret;
1375 }
1376
ohos_malloc_hook_munmap(void * addr,size_t length)1377 int ohos_malloc_hook_munmap(void* addr, size_t length)
1378 {
1379 __set_hook_flag(false);
1380 int ret = hook_munmap(GetDispatch()->munmap, addr, length);
1381 __set_hook_flag(true);
1382 return ret;
1383 }
1384
ohos_malloc_hook_memtrace(void * addr,size_t size,const char * tag,bool isUsing)1385 void ohos_malloc_hook_memtrace(void* addr, size_t size, const char* tag, bool isUsing)
1386 {
1387 __set_hook_flag(false);
1388 hook_memtrace(addr, size, tag, isUsing);
1389 __set_hook_flag(true);
1390 }
1391
ohos_malloc_hook_aligned_alloc(size_t align,size_t len)1392 void* ohos_malloc_hook_aligned_alloc(size_t align, size_t len)
1393 {
1394 __set_hook_flag(false);
1395 void* ret = hook_aligned_alloc(GetDispatch()->aligned_alloc, align, len);
1396 __set_hook_flag(true);
1397 return ret;
1398 }
1399
ohos_malloc_hook_prctl(int option,unsigned long arg2,unsigned long arg3,unsigned long arg4,unsigned long arg5)1400 int ohos_malloc_hook_prctl(int option, unsigned long arg2, unsigned long arg3,
1401 unsigned long arg4, unsigned long arg5)
1402 {
1403 __set_hook_flag(false);
1404 int ret = hook_prctl((GetDispatch()->prctl), option, arg2, arg3, arg4, arg5);
1405 __set_hook_flag(true);
1406 return ret;
1407 }
1408
ohos_set_filter_size(size_t size,void * ret)1409 bool ohos_set_filter_size(size_t size, void* ret)
1410 {
1411 if (g_ClientConfig.filterSize < 0 || size < static_cast<size_t>(g_ClientConfig.filterSize) || size > g_maxSize) {
1412 return false;
1413 }
1414 return true;
1415 }
1416
IsPidChanged(void)1417 static bool IsPidChanged(void)
1418 {
1419 if (g_isPidChanged) {
1420 return true;
1421 }
1422 int pid = getprocpid();
1423 // hap app after pid namespace used
1424 if (pid == PID_NAMESPACE_ID) {
1425 return false;
1426 } else {
1427 // native app & sa service
1428 g_isPidChanged = (g_hookPid != pid);
1429 }
1430 return g_isPidChanged;
1431 }
1432
ohos_malloc_hook_send_hook_misc_data(uint64_t id,const char * stackPtr,size_t stackSize,uint32_t type)1433 bool ohos_malloc_hook_send_hook_misc_data(uint64_t id, const char* stackPtr, size_t stackSize, uint32_t type)
1434 {
1435 if (type == static_cast<uint32_t>(MISC_TYPE::JS_STACK_DATA)) {
1436 StackRawData rawdata = {{{{0}}}};
1437 rawdata.jsChainId = id;
1438 rawdata.type = JS_STACK_MSG;
1439 std::weak_ptr<HookSocketClient> weakClient = g_hookClient;
1440 auto holder = weakClient.lock();
1441 if (holder != nullptr) {
1442 return holder->SendStackWithPayload(&rawdata, sizeof(BaseStackRawData), stackPtr, stackSize);
1443 }
1444 }
1445 return false;
1446 }
1447
ohos_malloc_hook_get_hook_config()1448 void* ohos_malloc_hook_get_hook_config()
1449 {
1450 return &g_ClientConfig.arktsConfig;
1451 }