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 }