• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2025. 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 "hook_record_factory.h"
17 #include <memory>
18 #include <string>
19 #include "hook_common.h"
20 #include "logging.h"
21 
22 namespace OHOS::Developtools::NativeDaemon {
23 
HookRecordFactory(NativeHookConfig hookConfig)24 HookRecordFactory::HookRecordFactory(NativeHookConfig hookConfig) : hookConfig_(hookConfig)
25 {
26     const bool isNoDataQueueMode = (hookConfig_.statistics_interval() > 0 && hookConfig_.fp_unwind() &&
27                                     hookConfig_.offline_symbolization());
28     int sharedMemCount = (hookConfig_.offline_symbolization()) ? SHARED_MEMORY_NUM : 1;
29     int rawDataCacheSize = isNoDataQueueMode ? sharedMemCount : RAW_DATA_CACHE_INIT_SIZE;
30     int hookRecordCacheSize = isNoDataQueueMode ? sharedMemCount : HOOK_RECORD_CACHE_INIT_SIZE;
31 
32     for (int index = 0; index < rawDataCacheSize; ++index) {
33         rawStackCache_.emplace_back(std::make_shared<RawStack>());
34     }
35     for (int index = 0; index < hookRecordCacheSize; ++index) {
36         mallocRecordCache_.emplace_back(std::make_shared<MallocRecord>());
37         mmapRecordCache_.emplace_back(std::make_shared<MmapRecord>());
38         munmapRecordCache_.emplace_back(std::make_shared<MunmapRecord>());
39         jsRecordCache_.emplace_back(std::make_shared<JsRecord>());
40         if (hookConfig_.statistics_interval() > 0) {
41             freeRecordSimpCache_.emplace_back(std::make_shared<FreeRecordSimp>());
42         } else {
43             freeRecordCache_.emplace_back(std::make_shared<FreeRecord>());
44         }
45     }
46 }
47 
CreateCacheItem(int16_t type)48 HookRecordPtr CreateCacheItem(int16_t type)
49 {
50     switch (type) {
51         case MALLOC_MSG:
52             return std::make_shared<MallocRecord>();
53         case FREE_MSG:
54             return std::make_shared<FreeRecord>();
55         case FREE_MSG_SIMP:
56             return std::make_shared<FreeRecordSimp>();
57         case MMAP_MSG:
58             return std::make_shared<MmapRecord>();
59         case MUNMAP_MSG:
60             return std::make_shared<MunmapRecord>();
61         case JS_STACK_MSG:
62             return std::make_shared<JsRecord>();
63         default:
64             PROFILER_LOG_ERROR(LOG_CORE, "CreateItem get unexpected type");
65             return nullptr;
66     }
67 }
68 
69 template <typename T>
GetRecordFromCache(std::deque<std::shared_ptr<T>> & dataCache,int16_t type)70 std::shared_ptr<T> HookRecordFactory::GetRecordFromCache(std::deque<std::shared_ptr<T>>& dataCache, int16_t type)
71 {
72     std::unique_lock<std::mutex> lock(recordMutex_);
73     if (!dataCache.empty()) {
74         std::shared_ptr<T> cachedData = std::move(dataCache.back());
75         dataCache.pop_back();
76         return cachedData;
77     }
78     return CreateCacheItem(type);
79 }
80 
GetRawStackFromCache()81 std::shared_ptr<RawStack> HookRecordFactory::GetRawStackFromCache()
82 {
83     std::unique_lock<std::mutex> lock(rawStackMutex_);
84     if (!rawStackCache_.empty()) {
85         std::shared_ptr<RawStack> cachedData = std::move(rawStackCache_.back());
86         rawStackCache_.pop_back();
87         return cachedData;
88     }
89     lock.unlock();
90     return std::make_shared<RawStack>();
91 }
92 
SaveRawStack(RawStackPtr rawStack)93 void HookRecordFactory::SaveRawStack(RawStackPtr rawStack)
94 {
95     std::unique_lock<std::mutex> rawStackLock(rawStackMutex_);
96     if (rawStack && (rawStackCache_.size() <= RAW_DATA_CACHE_MAX_SIZE)) {
97         rawStackCache_.push_back(std::move(rawStack));
98     }
99 }
100 
SaveRecordToCache(uint16_t type,HookRecordPtr hookRecord)101 void HookRecordFactory::SaveRecordToCache(uint16_t type, HookRecordPtr hookRecord)
102 {
103     switch (type) {
104         case FREE_MSG_SIMP:
105             if (freeRecordSimpCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
106                 freeRecordSimpCache_.push_back(hookRecord);
107             }
108             break;
109         case FREE_MSG:
110             if (freeRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
111                 freeRecordCache_.push_back(hookRecord);
112             }
113             break;
114         case MALLOC_MSG:
115             if (mallocRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
116                 mallocRecordCache_.push_back(hookRecord);
117             }
118             break;
119         case MMAP_MSG:
120             if (mmapRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
121                 mmapRecordCache_.push_back(hookRecord);
122             }
123             break;
124         case MUNMAP_MSG:
125             if (munmapRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
126                 munmapRecordCache_.push_back(hookRecord);
127             }
128             break;
129         case JS_STACK_MSG:
130             if (jsRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
131                 jsRecordCache_.push_back(hookRecord);
132             }
133             break;
134         default:
135             break;
136     }
137 }
138 
SaveHookRecord(HookRecordPtr hookRecord)139 void HookRecordFactory::SaveHookRecord(HookRecordPtr hookRecord)
140 {
141     if (hookRecord == nullptr) {
142         return;
143     }
144     auto rawStack = hookRecord->GetRawStack();
145     uint16_t type = hookRecord->GetType();
146     hookRecord->Reset();
147     SaveRawStack(std::move(rawStack));
148     std::unique_lock<std::mutex> lock(recordMutex_);
149     SaveRecordToCache(type, std::move(hookRecord));
150 }
151 
CreateStackRecord(uint16_t type,RawStackPtr rawStack)152 std::shared_ptr<HookRecord> HookRecordFactory::CreateStackRecord(uint16_t type, RawStackPtr rawStack)
153 {
154     switch (type) {
155         case MMAP_FILE_PAGE_MSG:
156             return std::make_shared<MmapFilePageRecord>(rawStack);
157         case MUNMAP_MSG: {
158             auto munmapRecord = GetRecordFromCache(munmapRecordCache_, MUNMAP_MSG);
159             munmapRecord->rawStack_ = rawStack;
160             return munmapRecord;
161         }
162         case MEMORY_UNUSING_MSG:
163             return std::make_shared<MemoryUnusingRecord>(rawStack);
164         case MEMORY_USING_MSG:
165             return std::make_shared<MemoryUsingRecord>(rawStack);
166         case MMAP_FILE_TYPE:
167             return std::make_shared<TagRecord>(rawStack);
168         case MALLOC_MSG: {
169             auto mallocRecord = GetRecordFromCache(mallocRecordCache_, MALLOC_MSG);
170             mallocRecord->rawStack_ = rawStack;
171             return mallocRecord;
172         }
173         case MMAP_MSG: {
174             auto mmapRecord = GetRecordFromCache(mmapRecordCache_, MMAP_MSG);
175             mmapRecord->rawStack_ = rawStack;
176             return mmapRecord;
177         }
178         case FREE_MSG: {
179             auto freeRecord = GetRecordFromCache(freeRecordCache_, FREE_MSG);
180             freeRecord->rawStack_ = rawStack;
181             return freeRecord;
182         }
183         default:
184             PROFILER_LOG_ERROR(LOG_CORE, "GetHookRecord get unknown type");
185             return nullptr;
186     }
187 }
188 
InitRawStack(RawStackPtr rawStack,const int8_t sharedMemData[],uint32_t size,bool storeData)189 void HookRecordFactory::InitRawStack(RawStackPtr rawStack, const int8_t sharedMemData[],
190                                      uint32_t size, bool storeData)
191 {
192     if (storeData) {
193         rawStack->baseStackData = std::make_unique<uint8_t[]>(size);
194         if (memcpy_s(rawStack->baseStackData.get(), size, sharedMemData, size) != EOK) {
195             PROFILER_LOG_ERROR(LOG_CORE, "HookRecordFactory memcpy_s raw data failed!");
196             return;
197         }
198         rawStack->stackContext = reinterpret_cast<BaseStackRawData*>(rawStack->baseStackData.get());
199         rawStack->data = rawStack->baseStackData.get() + sizeof(BaseStackRawData);
200     } else {
201         rawStack->stackContext = reinterpret_cast<BaseStackRawData*>(const_cast<int8_t*>(sharedMemData));
202         rawStack->data = reinterpret_cast<uint8_t*>(const_cast<int8_t*>(sharedMemData)) + sizeof(BaseStackRawData);
203     }
204 }
205 
GetHookRecord(const int8_t sharedMemData[],uint32_t size,bool storeData)206 std::shared_ptr<HookRecord> HookRecordFactory::GetHookRecord(const int8_t sharedMemData[],
207                                                              uint32_t size, bool storeData)
208 {
209     if (size == sizeof(void*)) {
210         uint64_t freeAddr = 0;
211         if (memcpy_s(&freeAddr, sizeof(freeAddr), sharedMemData, size) != EOK) {
212             PROFILER_LOG_ERROR(LOG_CORE, "GetHookRecord memcpy failed");
213             return nullptr;
214         }
215         auto freeRecord = GetRecordFromCache(freeRecordSimpCache_, FREE_MSG_SIMP);
216         freeRecord->SetAddr(freeAddr);
217         return freeRecord;
218     }
219     auto rawStack = GetRawStackFromCache();
220     InitRawStack(rawStack, sharedMemData, size, storeData);
221     uint16_t type = rawStack->stackContext->type;
222     switch (type) {
223         case NMD_MSG:
224             return std::make_shared<NmdRecord>(rawStack);
225         case END_MSG:
226         case MEMORY_TAG:
227         case THREAD_NAME_MSG:
228             return std::make_shared<TagRecord>(rawStack);
229         case PR_SET_VMA_MSG:
230             return std::make_shared<PrSetVmaRecord>(rawStack);
231         case JS_STACK_MSG: {
232             auto jsRecord = GetRecordFromCache(jsRecordCache_, JS_STACK_MSG);
233             jsRecord->rawStack_ = rawStack;
234             return jsRecord;
235         }
236         default:
237             break;
238     }
239 
240     if (hookConfig_.fp_unwind()) {
241         rawStack->fpDepth = (size - sizeof(BaseStackRawData)) / sizeof(uint64_t);
242     } else {
243         size_t rawRealSize = sizeof(BaseStackRawData) + MAX_REG_SIZE * sizeof(char);
244         rawStack->stackSize = size - rawRealSize;
245         if (rawStack->stackSize > 0) {
246             rawStack->stackData = rawStack->baseStackData.get() + rawRealSize;
247         }
248     }
249     return CreateStackRecord(type, rawStack);
250 }
251 }