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